Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec3afaaf36 | ||
|
|
9f978591ff | ||
|
|
7fff58d8f9 | ||
|
|
6192bd8dce | ||
|
|
be43a2a5d4 | ||
|
|
99524bf043 | ||
|
|
f2144ab446 | ||
|
|
ada045a13b | ||
|
|
4c4f7e5b92 | ||
|
|
ef521207de | ||
|
|
3ef0f7e0f1 | ||
|
|
74808cdd3a | ||
|
|
1e8d08ee3a | ||
|
|
8d8a1e122e | ||
|
|
fe62c05b4b | ||
|
|
f93d03dbd3 | ||
|
|
7eb5c7c208 | ||
|
|
e04c3ee2fd | ||
|
|
38a1e90aad | ||
|
|
83d459021b | ||
|
|
fb8dcb9fb4 | ||
|
|
5e73b59d06 | ||
|
|
bca28781bd | ||
|
|
899e94c5bc | ||
|
|
0a7cb40dbc | ||
|
|
bd8576df0c | ||
|
|
49f19abb91 | ||
|
|
300b7bbbdd | ||
|
|
bbee5bef25 | ||
|
|
1fc1cef233 | ||
|
|
ae9a6695b0 | ||
|
|
572704fd73 | ||
|
|
dfe3cc8480 | ||
|
|
97ae63693a | ||
|
|
940996aa30 | ||
|
|
2a4cfb0684 | ||
|
|
061a0fa11b | ||
|
|
41462137d6 | ||
|
|
9888dfe678 | ||
|
|
baa027bc41 | ||
|
|
8f2e835e9c | ||
|
|
8333fe3621 | ||
|
|
291808a564 | ||
|
|
900d0bc9b5 | ||
|
|
6fe4d2a171 | ||
|
|
1076693322 | ||
|
|
5a9e66b7c9 | ||
|
|
b1d0175a9d | ||
|
|
6ac332834d | ||
|
|
32711449b2 | ||
|
|
c18ff9d2b4 | ||
|
|
ce908f0033 | ||
|
|
1a70f87897 | ||
|
|
c07fb4ddf3 | ||
|
|
1458fb0aaa | ||
|
|
57b8209b26 | ||
|
|
a7224755ff | ||
|
|
e97168c62e | ||
|
|
1e8dd405c3 | ||
|
|
830e9de56b | ||
|
|
2a06002b51 | ||
|
|
84b1b6a7eb |
@@ -3,6 +3,7 @@
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="res"/>
|
||||
<classpathentry kind="src" path="hacked-libtiled"/>
|
||||
<classpathentry kind="src" path="siphash-zackehh/src/main/java"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="lib" path="lib/jide-oss.jar"/>
|
||||
<classpathentry kind="lib" path="lib/json_simple-1.1.jar"/>
|
||||
@@ -11,6 +12,7 @@
|
||||
<classpathentry kind="lib" path="lib/rsyntaxtextarea.jar"/>
|
||||
<classpathentry kind="lib" path="lib/ui.jar"/>
|
||||
<classpathentry kind="lib" path="lib/bsh-2.0b4.jar"/>
|
||||
<classpathentry kind="lib" path="lib/AndorsTrainer_v0.1.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jsoup-1.10.2.jar" sourcepath="lib/jsoup-1.10.2-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/AndorsTrainer_v0.1.4.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
||||
19
ATCS_JAR.jardesc
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="WINDOWS-1252" standalone="no"?>
|
||||
<jardesc>
|
||||
<jar path="ATCS/ATCS_v0.6.5.jar"/>
|
||||
<options buildIfNeeded="true" compress="true" descriptionLocation="/ATCS/ATCS_JAR.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
|
||||
<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
|
||||
<selectedProjects/>
|
||||
<manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
|
||||
<sealing sealJar="false">
|
||||
<packagesToSeal/>
|
||||
<packagesToUnSeal/>
|
||||
</sealing>
|
||||
</manifest>
|
||||
<selectedElements exportClassFiles="true" exportJavaFiles="true" exportOutputFolder="false">
|
||||
<javaElement handleIdentifier="=ATCS/res"/>
|
||||
<javaElement handleIdentifier="=ATCS/src"/>
|
||||
<javaElement handleIdentifier="=ATCS/siphash-zackehh\/src\/main\/java"/>
|
||||
<javaElement handleIdentifier="=ATCS/hacked-libtiled"/>
|
||||
</selectedElements>
|
||||
</jardesc>
|
||||
@@ -29,7 +29,9 @@
|
||||
package tiled.core;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.util.*;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* The Map class is the focal point of the <code>tiled.core</code> package.
|
||||
@@ -109,11 +111,14 @@ public class Map implements Iterable<MapLayer>
|
||||
|
||||
public MapLayer addLayer(MapLayer layer) {
|
||||
layer.setMap(this);
|
||||
layers.add(layer);
|
||||
if (layer instanceof TileLayer) {
|
||||
tileLayers.add((TileLayer) layer);
|
||||
layers.add(layer);
|
||||
} else if (layer instanceof ObjectGroup) {
|
||||
layers.insertElementAt(layer, objectGroups.size());
|
||||
objectGroups.add((ObjectGroup) layer);
|
||||
} else {
|
||||
layers.add(layer);
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
|
||||
@@ -28,10 +28,12 @@
|
||||
|
||||
package tiled.core;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Properties;
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,8 +33,8 @@ import java.awt.Shape;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
package tiled.core;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
@@ -36,7 +36,7 @@ import java.util.Properties;
|
||||
*/
|
||||
public class Tile
|
||||
{
|
||||
private Image image;
|
||||
private BufferedImage image;
|
||||
private int id = -1;
|
||||
private Properties properties;
|
||||
private TileSet tileset;
|
||||
@@ -76,7 +76,7 @@ public class Tile
|
||||
*
|
||||
* @param i the new image of the tile
|
||||
*/
|
||||
public void setImage(Image i) {
|
||||
public void setImage(BufferedImage i) {
|
||||
image = i;
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ public class Tile
|
||||
*
|
||||
* @return Image
|
||||
*/
|
||||
public Image getImage() {
|
||||
public BufferedImage getImage() {
|
||||
if (tileset != null && tileset.sheet != null) return tileset.sheet.getImage(getId());
|
||||
return image;
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ public class TileSet implements Iterable<Tile>
|
||||
tilesPerRow = basicTileCutter.getTilesPerRow();
|
||||
}
|
||||
|
||||
Image tileImage = cutter.getNextTile();
|
||||
BufferedImage tileImage = cutter.getNextTile();
|
||||
while (tileImage != null) {
|
||||
Tile tile = new Tile();
|
||||
tile.setImage(tileImage);
|
||||
@@ -220,7 +220,7 @@ public class TileSet implements Iterable<Tile>
|
||||
tileDimensions = new Rectangle(tileCutter.getTileDimensions());
|
||||
|
||||
int id = 0;
|
||||
Image tileImage = tileCutter.getNextTile();
|
||||
BufferedImage tileImage = tileCutter.getNextTile();
|
||||
while (tileImage != null) {
|
||||
Tile tile = getTile(id);
|
||||
tile.setImage(tileImage);
|
||||
|
||||
@@ -31,13 +31,13 @@ package tiled.io;
|
||||
import java.awt.Color;
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -223,9 +223,9 @@ public class TMXMapReader
|
||||
return o;
|
||||
}
|
||||
|
||||
private Image unmarshalImage(Node t, String baseDir) throws IOException
|
||||
private BufferedImage unmarshalImage(Node t, String baseDir) throws IOException
|
||||
{
|
||||
Image img = null;
|
||||
BufferedImage img = null;
|
||||
|
||||
String source = getAttributeValue(t, "source");
|
||||
|
||||
@@ -253,7 +253,7 @@ public class TMXMapReader
|
||||
// size, somehow makes drawing of the tiles a lot
|
||||
// faster on various systems (seen on Linux, Windows
|
||||
// and MacOS X).
|
||||
img = img.getScaledInstance(
|
||||
img = (BufferedImage) img.getScaledInstance(
|
||||
img.getWidth(null), img.getHeight(null),
|
||||
Image.SCALE_FAST);
|
||||
}
|
||||
@@ -534,7 +534,7 @@ public class TMXMapReader
|
||||
Node child = children.item(i);
|
||||
if ("image".equalsIgnoreCase(child.getNodeName())) {
|
||||
int id = getAttribute(child, "id", -1);
|
||||
Image img = unmarshalImage(child, baseDir);
|
||||
BufferedImage img = unmarshalImage(child, baseDir);
|
||||
tile.setImage(img);
|
||||
} else if ("animation".equalsIgnoreCase(child.getNodeName())) {
|
||||
// TODO: fill this in once TMXMapWriter is complete
|
||||
|
||||
@@ -30,14 +30,32 @@ package tiled.io;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Rectangle;
|
||||
import java.io.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Vector;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import tiled.core.*;
|
||||
import tiled.core.AnimatedTile;
|
||||
import tiled.core.Map;
|
||||
import tiled.core.MapLayer;
|
||||
import tiled.core.MapObject;
|
||||
import tiled.core.ObjectGroup;
|
||||
import tiled.core.Sprite;
|
||||
import tiled.core.Tile;
|
||||
import tiled.core.TileLayer;
|
||||
import tiled.core.TileSet;
|
||||
import tiled.io.xml.XMLWriter;
|
||||
import tiled.util.Base64;
|
||||
|
||||
@@ -163,7 +181,12 @@ public class TMXMapWriter
|
||||
firstgid += tileset.getMaxTileId() + 1;
|
||||
}
|
||||
|
||||
for (MapLayer layer : map) {
|
||||
for (MapLayer layer : map.getTileLayers()) {
|
||||
writeMapLayer(layer, w, wp);
|
||||
}
|
||||
|
||||
for (MapLayer layer : map.getObjectGroup()) {
|
||||
if (map.getTileLayers().contains(layer)) continue;
|
||||
writeMapLayer(layer, w, wp);
|
||||
}
|
||||
firstGidPerTileset = null;
|
||||
|
||||
@@ -28,9 +28,8 @@
|
||||
|
||||
package tiled.io.xml;
|
||||
|
||||
import java.lang.String;
|
||||
import java.io.Writer;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
package tiled.util;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
@@ -64,7 +63,7 @@ public class BasicTileCutter implements TileCutter
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public Image getNextTile() {
|
||||
public BufferedImage getNextTile() {
|
||||
if (nextY + tileHeight + tileMargin <= image.getHeight()) {
|
||||
BufferedImage tile =
|
||||
image.getSubimage(nextX, nextY, tileWidth, tileHeight);
|
||||
|
||||
@@ -33,6 +33,7 @@ import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
package tiled.util;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
@@ -48,7 +47,7 @@ public interface TileCutter
|
||||
* @return the next tile image, or <code>null</code> when no more tile
|
||||
* images are available
|
||||
*/
|
||||
public Image getNextTile();
|
||||
public BufferedImage getNextTile();
|
||||
|
||||
/**
|
||||
* Resets the tile cutter so that the next call to <code>getNextTile</code>
|
||||
|
||||
@@ -27,9 +27,10 @@
|
||||
|
||||
package tiled.view;
|
||||
|
||||
import tiled.core.TileLayer;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import java.awt.*;
|
||||
import tiled.core.TileLayer;
|
||||
|
||||
/**
|
||||
* An interface defining methods to render a map.
|
||||
|
||||
@@ -27,12 +27,15 @@
|
||||
|
||||
package tiled.view;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import tiled.core.Map;
|
||||
import tiled.core.Tile;
|
||||
import tiled.core.TileLayer;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* The orthogonal map renderer. This is the most basic map renderer, dealing
|
||||
* with maps that use rectangular tiles.
|
||||
@@ -74,10 +77,12 @@ public class OrthogonalRenderer implements MapRenderer
|
||||
final Tile tile = layer.getTileAt(x, y);
|
||||
if (tile == null)
|
||||
continue;
|
||||
final Image image = tile.getImage();
|
||||
final BufferedImage image = tile.getImage();
|
||||
if (image == null)
|
||||
continue;
|
||||
|
||||
|
||||
|
||||
g.drawImage(
|
||||
image,
|
||||
x * tileWidth,
|
||||
|
||||
BIN
itemScroll.xcf
Normal file
BIN
lib/AndorsTrainer_v0.1.4.jar
Normal file
BIN
lib/jsoup-1.10.2-sources.jar
Normal file
BIN
lib/jsoup-1.10.2.jar
Normal file
1
packaging/ATCS_latest
Normal file
@@ -0,0 +1 @@
|
||||
v0.6.5
|
||||
@@ -1 +1,20 @@
|
||||
start "" "javaw.exe" -Xmx512M -cp "lib\jide-oss.jar;lib\ui.jar;lib\junit-4.10.jar;lib\json_simple-1.1.jar;lib\rsyntaxtextarea.jar;lib\prefuse.jar;lib\ATCS_v0.4.3.jar;lib\AndorsTrainer_v0.1.2.jar;lib\bsh-2.0b4.jar" com.gpl.rpg.atcontentstudio.ATContentStudio
|
||||
@echo off
|
||||
|
||||
set "ATCS_DIR=%~dp0"
|
||||
set "MAX_MEM=512M"
|
||||
set "CP=%ATCS_DIR%lib\*"
|
||||
set "JAVA=javaw.exe"
|
||||
set "JAVA_OPTS="
|
||||
set "ENV_FILE=%ATCS_DIR%ATCS.env.bat"
|
||||
set "MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio"
|
||||
|
||||
if exist "%ENV_FILE%" (
|
||||
call "%ENV_FILE%"
|
||||
) else (
|
||||
echo REM set "MAX_MEM=%MAX_MEM%">"%ENV_FILE%"
|
||||
echo REM set "JAVA=%JAVA%">>"%ENV_FILE%"
|
||||
echo REM set "JAVA_OPTS=%JAVA_OPTS%">>"%ENV_FILE%"
|
||||
echo.>>"%ENV_FILE%"
|
||||
)
|
||||
|
||||
start "" "%JAVA%" %JAVA_OPTS% -Xmx%MAX_MEM% -cp "%CP%" %MAIN_CLASS%
|
||||
|
||||
@@ -1,2 +1,22 @@
|
||||
#!/bin/bash
|
||||
java -Xmx512M -cp lib/AndorsTrainer_v0.1.2.jar:lib/ATCS_v0.4.3.jar:lib/prefuse.jar:lib/json_simple-1.1.jar:lib/jide-oss.jar:lib/ui.jar:lib/junit-4.10.jar:lib/rsyntaxtextarea.jar:lib/bsh-2.0b4.jar com.gpl.rpg.atcontentstudio.ATContentStudio
|
||||
ATCS_DIR=$(dirname $(readlink -f "$0" || greadlink -f "$0" || stat -f "$0"))
|
||||
MAX_MEM=512M
|
||||
CP=$(find ${ATCS_DIR}/lib/ -name '*.jar' | paste -sd: -)
|
||||
JAVA=java
|
||||
JAVA_OPTS=
|
||||
ENV_FILE=${ATCS_DIR}/ATCS.env
|
||||
MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio
|
||||
|
||||
if [ -f ${ENV_FILE} ]
|
||||
then
|
||||
source ${ENV_FILE}
|
||||
else
|
||||
echo "#MAX_MEM=${MAX_MEM}" > ${ENV_FILE}
|
||||
echo "#JAVA=${JAVA}" >> ${ENV_FILE}
|
||||
echo "#JAVA_OPTS=${JAVA_OPTS}" >> ${ENV_FILE}
|
||||
echo "" >> ${ENV_FILE}
|
||||
fi
|
||||
|
||||
export ENV_FILE
|
||||
|
||||
$JAVA ${JAVA_OPTS} -Xmx${MAX_MEM} -cp ${CP} ${MAIN_CLASS}
|
||||
|
||||
@@ -1 +1,20 @@
|
||||
start "" "javaw.exe" -Xmx512M -cp "lib\jide-oss.jar;lib\ui.jar;lib\junit-4.10.jar;lib\json_simple-1.1.jar;lib\rsyntaxtextarea.jar;lib\prefuse.jar;lib\ATCS_v0.4.3.jar;lib\AndorsTrainer_v0.1.2.jar;lib\bsh-2.0b4.jar" com.gpl.rpg.atcontentstudio.ATContentStudio
|
||||
@echo off
|
||||
|
||||
set "ATCS_DIR=%~dp0"
|
||||
set "MAX_MEM=512M"
|
||||
set "CP=%ATCS_DIR%lib\*"
|
||||
set "JAVA=javaw.exe"
|
||||
set "JAVA_OPTS="
|
||||
set "ENV_FILE=%ATCS_DIR%ATCS.env.bat"
|
||||
set "MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio"
|
||||
|
||||
if exist "%ENV_FILE%" (
|
||||
call "%ENV_FILE%"
|
||||
) else (
|
||||
echo REM set "MAX_MEM=%MAX_MEM%">"%ENV_FILE%"
|
||||
echo REM set "JAVA=%JAVA%">>"%ENV_FILE%"
|
||||
echo REM set "JAVA_OPTS=%JAVA_OPTS%">>"%ENV_FILE%"
|
||||
echo.>>"%ENV_FILE%"
|
||||
)
|
||||
|
||||
start "" "%JAVA%" %JAVA_OPTS% -Xmx%MAX_MEM% -cp "%CP%" %MAIN_CLASS%
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
!include MUI2.nsh
|
||||
|
||||
!define VERSION "0.4.3"
|
||||
!define JAVA_BIN "java"
|
||||
!define VERSION "0.6.5"
|
||||
!define TRAINER_VERSION "0.1.4"
|
||||
!define JAVA_BIN "javaw"
|
||||
|
||||
Name "Andor's Trail Content Studio v${VERSION}"
|
||||
OutFile "ATCS_v${VERSION}_Setup.exe"
|
||||
@@ -54,22 +55,44 @@ Section install
|
||||
SetOutPath $INSTDIR
|
||||
file "ATCS.ico"
|
||||
|
||||
Delete "$INSTDIR\lib\*"
|
||||
|
||||
Call GetJRE
|
||||
Pop $R0
|
||||
FileOpen $9 "ATCS.cmd" w
|
||||
FileWrite $9 'start "" "$R0" -Xmx512M -cp "lib\AndorsTrainer_v0.1.1.jar;lib\jide-oss.jar;lib\ui.jar;lib\junit-4.10.jar;lib\json_simple-1.1.jar;lib\rsyntaxtextarea.jar;lib\prefuse.jar;lib\bsh-2.0b4.jar;lib\ATCS_v${VERSION}.jar" com.gpl.rpg.atcontentstudio.ATContentStudio'
|
||||
FileWrite $9 '@echo off$\r$\n'
|
||||
FileWrite $9 '$\r$\n'
|
||||
FileWrite $9 'set "ATCS_DIR=%~dp0"$\r$\n'
|
||||
FileWrite $9 'set "MAX_MEM=512M"$\r$\n'
|
||||
FileWrite $9 'set "CP=%ATCS_DIR%lib\*"$\r$\n'
|
||||
FileWrite $9 'set "JAVA=$R0"$\r$\n'
|
||||
FileWrite $9 'set "JAVA_OPTS="$\r$\n'
|
||||
FileWrite $9 'set "ENV_FILE=%ATCS_DIR%ATCS.env.bat"$\r$\n'
|
||||
FileWrite $9 'set "MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio"$\r$\n'
|
||||
FileWrite $9 '$\r$\n'
|
||||
FileWrite $9 'if exist "%ENV_FILE%" ($\r$\n'
|
||||
FileWrite $9 ' call "%ENV_FILE%"$\r$\n'
|
||||
FileWrite $9 ') else ($\r$\n'
|
||||
FileWrite $9 ' echo REM set "MAX_MEM=%MAX_MEM%">"%ENV_FILE%"$\r$\n'
|
||||
FileWrite $9 ' echo REM set "JAVA=%JAVA%">>"%ENV_FILE%"$\r$\n'
|
||||
FileWrite $9 ' echo REM set "JAVA_OPTS=%JAVA_OPTS%">>"%ENV_FILE%"$\r$\n'
|
||||
FileWrite $9 ' echo.>>"%ENV_FILE%"$\r$\n'
|
||||
FileWrite $9 ')$\r$\n'
|
||||
FileWrite $9 '$\r$\n'
|
||||
FileWrite $9 'start "" "%JAVA%" %JAVA_OPTS% -Xmx%MAX_MEM% -cp "%CP%" %MAIN_CLASS%$\r$\n'
|
||||
FileClose $9
|
||||
|
||||
SetOutPath "$INSTDIR\lib\"
|
||||
file "jide-oss.jar"
|
||||
file "ui.jar"
|
||||
file "AndorsTrainer_v0.1.2.jar"
|
||||
file "AndorsTrainer_v${TRAINER_VERSION}.jar"
|
||||
file "junit-4.10.jar"
|
||||
file "json_simple-1.1.jar"
|
||||
file "ATCS_v${VERSION}.jar"
|
||||
file "rsyntaxtextarea.jar"
|
||||
file "prefuse.jar"
|
||||
file "bsh-2.0b4.jar"
|
||||
file "jsoup-1.10.2.jar"
|
||||
|
||||
SetOutPath $INSTDIR
|
||||
|
||||
@@ -93,13 +116,16 @@ Section uninstall
|
||||
Delete "$INSTDIR\lib\ui.jar"
|
||||
Delete "$INSTDIR\lib\junit-4.10.jar"
|
||||
Delete "$INSTDIR\lib\json_simple-1.1.jar"
|
||||
Delete "$INSTDIR\lib\AndorsTrainer_v0.1.2.jar"
|
||||
Delete "$INSTDIR\lib\AndorsTrainer_v${TRAINER_VERSION}.jar"
|
||||
Delete "$INSTDIR\lib\ATCS_v${VERSION}.jar"
|
||||
Delete "$INSTDIR\lib\rsyntaxtextarea.jar"
|
||||
Delete "$INSTDIR\lib\prefuse.jar"
|
||||
Delete "$INSTDIR\lib\bsh-2.0b4.jar"
|
||||
Delete "$INSTDIR\lib\jsoup-1.10.2.jar"
|
||||
RMDir "$INSTDIR\lib\"
|
||||
Delete "$INSTDIR\ATCS.ico"
|
||||
Delete "$INSTDIR\ATCS.cmd"
|
||||
Delete "$INSTDIR\ATCS.env.bat"
|
||||
|
||||
Delete "$INSTDIR\Uninstall.exe"
|
||||
|
||||
|
||||
21
res/LICENSE.jsoup.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License
|
||||
|
||||
© 2009-2017, Jonathan Hedley <jonathan@hedley.net>
|
||||
|
||||
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 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.
|
||||
21
res/LICENSE.siphash-zackehh.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Isaac Whitfield
|
||||
|
||||
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 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.
|
||||
@@ -1,5 +1,6 @@
|
||||
atcs.spritesheet.actorconditions_1.category=actorcondition
|
||||
atcs.spritesheet.actorconditions_2.category=actorcondition
|
||||
atcs.spritesheet.actorconditions_japozero.category=actorcondition
|
||||
atcs.spritesheet.items_armours.category=item
|
||||
atcs.spritesheet.items_armours_2.category=item
|
||||
atcs.spritesheet.items_armours_3.category=item
|
||||
@@ -10,6 +11,7 @@ atcs.spritesheet.items_jewelry.category=item
|
||||
atcs.spritesheet.items_rings_1.category=item
|
||||
atcs.spritesheet.items_necklaces_1.category=item
|
||||
atcs.spritesheet.items_consumables.category=item
|
||||
atcs.spritesheet.items_japozero.category=item
|
||||
atcs.spritesheet.items_books.category=item
|
||||
atcs.spritesheet.items_misc.category=item
|
||||
atcs.spritesheet.items_misc_2.category=item
|
||||
|
||||
19
siphash-zackehh/.gitignore
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
*.class
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
# build
|
||||
target
|
||||
3
siphash-zackehh/.travis.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
language: java
|
||||
script:
|
||||
- mvn clean test jacoco:report coveralls:report
|
||||
21
siphash-zackehh/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Isaac Whitfield
|
||||
|
||||
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 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.
|
||||
77
siphash-zackehh/README.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# SipHash
|
||||
|
||||
[](https://travis-ci.org/zackehh/siphash-java) [](https://coveralls.io/github/zackehh/siphash-java?branch=master)
|
||||
|
||||
A Java implementation of the SipHash cryptographic hash family. Supports any variation, although defaults to the widely used SipHash-2-4. Can be used with either full input, or used as a streaming digest.
|
||||
|
||||
This library was heavily influenced by [veorq's C implementation](https://github.com/veorq/siphash) and [Forward C&C's reference implementation](http://www.forward.com.au/pfod/SipHashJavaLibrary/) - I just decided it was time a Java implementation of SipHash made it onto Maven :).
|
||||
|
||||
## Setup
|
||||
|
||||
`siphash` is available on Maven central, via Sonatype OSS:
|
||||
|
||||
```
|
||||
<dependency>
|
||||
<groupId>com.zackehh</groupId>
|
||||
<artifactId>siphash</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
There are two ways of using SipHash (see below). Both return a `SipHashResult` which can be used to retrieve the result in various forms. All constructors can take arguments to specify the compression rounds. For further usage, please visit the [documentation](http://www.javadoc.io/doc/com.zackehh/siphash).
|
||||
|
||||
#### Full Input Hash
|
||||
|
||||
The first is to simple create a `SipHash` instance and use it to repeatedly hash using the same key.
|
||||
|
||||
The internal state is immutable, so you can hash many inputs without having to recreate a new `SipHash` instance (unless you want a new key).
|
||||
|
||||
```java
|
||||
SipHash hasher = new SipHash("0123456789ABCDEF".getBytes());
|
||||
|
||||
SipHashResult result = hasher.hash("my-input".getBytes());
|
||||
|
||||
System.out.println(result.get()); // 182795880124085484 <-- this can overflow
|
||||
System.out.println(result.getHex()); // "2896be26d3374ec"
|
||||
System.out.println(result.getHex(true)); // "02896be26d3374ec"
|
||||
System.out.println(result.getHex(SipHashCase.UPPER)); // "2896BE26D3374EC"
|
||||
System.out.println(result.getHex(true, SipHashCase.UPPER)); // "02896BE26D3374EC"
|
||||
```
|
||||
|
||||
#### Streaming Hash
|
||||
|
||||
The second is to use the library as a streaming hash, meaning you can apply chunks of bytes to the hash as they become available.
|
||||
|
||||
Using this method you must create a new digest every time you want to hash a different input as the internal state is mutable.
|
||||
|
||||
```java
|
||||
SipHashDigest digest = new SipHashDigest("0123456789ABCDEF".getBytes());
|
||||
|
||||
digest.update("chu".getBytes());
|
||||
digest.update("nked".getBytes());
|
||||
digest.update(" string".getBytes());
|
||||
|
||||
SipHashResult result = digest.finish();
|
||||
|
||||
System.out.println(result.get()); // 3502906798476177428 <-- this can overflow
|
||||
System.out.println(result.getHex()); // "309cd32c8c793014"
|
||||
System.out.println(result.getHex(true)); // "309cd32c8c793014"
|
||||
System.out.println(result.getHex(SipHashCase.UPPER)); // "309CD32C8C793014"
|
||||
System.out.println(result.getHex(true, SipHashCase.UPPER)); // "309CD32C8C793014"
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
If you wish to contribute (awesome!), please file an issue first! All PRs should pass `mvn clean verify` and maintain 100% test coverage.
|
||||
|
||||
## Testing
|
||||
|
||||
Tests are run using `mvn`. I aim to maintain 100% coverage where possible (both line and branch).
|
||||
|
||||
Tests can be run as follows:
|
||||
|
||||
```bash
|
||||
$ mvn clean verify
|
||||
```
|
||||
171
siphash-zackehh/pom.xml
Normal file
@@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.zackehh</groupId>
|
||||
<artifactId>siphash</artifactId>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>SipHash</name>
|
||||
<description>
|
||||
A SipHash implementation in Java.
|
||||
</description>
|
||||
<url>https://github.com/zackehh/siphash-java</url>
|
||||
|
||||
<properties>
|
||||
<jacoco.version>0.7.5.201505241946</jacoco.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>iwhitfield</id>
|
||||
<name>Isaac Whitfield</name>
|
||||
<email>iw@zackehh.com</email>
|
||||
<organization>Appcelerator, Inc.</organization>
|
||||
<organizationUrl>http://www.appcelerator.com</organizationUrl>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:zackehh/siphash-java.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:zackehh/siphash-java.git</developerConnection>
|
||||
<url>git@github.com:zackehh/siphash-java.git</url>
|
||||
</scm>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT License</name>
|
||||
<url>http://www.opensource.org/licenses/mit-license.php</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>ossrh</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>ossrh</id>
|
||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<version>6.8.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
<version>1.6.3</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<serverId>ossrh</serverId>
|
||||
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
|
||||
<autoReleaseAfterClose>false</autoReleaseAfterClose>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.3</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${jacoco.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eluder.coveralls</groupId>
|
||||
<artifactId>coveralls-maven-plugin</artifactId>
|
||||
<version>4.1.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
106
siphash-zackehh/src/main/java/com/zackehh/siphash/SipHash.java
Normal file
@@ -0,0 +1,106 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
import static com.zackehh.siphash.SipHashConstants.*;
|
||||
|
||||
/**
|
||||
* Main entry point for SipHash, providing a basic hash
|
||||
* interface. Assuming you have your full String to hash,
|
||||
* you can simply provide it to ${@link SipHash#hash(byte[])}.
|
||||
*
|
||||
* This class can be initialized and stored in case the
|
||||
* developer wishes to use the same key over and over again.
|
||||
*
|
||||
* This avoids the overhead of having to create the initial
|
||||
* key over and over again.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* List<String> inputs = Arrays.asList("input1", "input2", "input3");
|
||||
* SipHash hasher = new SipHash("this key is mine".getBytes());
|
||||
* for (int i = 0; i < inputs.size(); i++) {
|
||||
* hasher.hash(inputs.get(i));
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class SipHash {
|
||||
|
||||
/**
|
||||
* The values of SipHash-c-d, to determine which of the SipHash
|
||||
* family we're using for this hash.
|
||||
*/
|
||||
private final int c, d;
|
||||
|
||||
/**
|
||||
* Initial seeded value of v0.
|
||||
*/
|
||||
private final long v0;
|
||||
|
||||
/**
|
||||
* Initial seeded value of v1.
|
||||
*/
|
||||
private final long v1;
|
||||
|
||||
/**
|
||||
* Initial seeded value of v2.
|
||||
*/
|
||||
private final long v2;
|
||||
|
||||
/**
|
||||
* Initial seeded value of v3.
|
||||
*/
|
||||
private final long v3;
|
||||
|
||||
/**
|
||||
* Accepts a 16 byte key input, and uses it to initialize
|
||||
* the state of the hash. This uses the default values of
|
||||
* c/d, meaning that we default to SipHash-2-4.
|
||||
*
|
||||
* @param key a 16 byte key input
|
||||
*/
|
||||
public SipHash(byte[] key){
|
||||
this(key, DEFAULT_C, DEFAULT_D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a 16 byte key input, and uses it to initialize
|
||||
* the state of the hash. This constructor allows for
|
||||
* providing the c/d values, allowing the developer to
|
||||
* select any of the SipHash family to use for hashing.
|
||||
*
|
||||
* @param key a 16 byte key input
|
||||
* @param c the number of compression rounds
|
||||
* @param d the number of finalization rounds
|
||||
*/
|
||||
public SipHash(byte[] key, int c, int d){
|
||||
this.c = c;
|
||||
this.d = d;
|
||||
|
||||
SipHashKey hashKey = new SipHashKey(key);
|
||||
|
||||
this.v0 = (INITIAL_V0 ^ hashKey.k0);
|
||||
this.v1 = (INITIAL_V1 ^ hashKey.k1);
|
||||
this.v2 = (INITIAL_V2 ^ hashKey.k0);
|
||||
this.v3 = (INITIAL_V3 ^ hashKey.k1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The basic hash implementation provided in the library.
|
||||
* Assuming you have your full input, you can provide it and
|
||||
* it will be hashed based on the values which were provided
|
||||
* to the constructor of this class.
|
||||
*
|
||||
* @param data the bytes to hash
|
||||
* @return a ${@link SipHashResult} instance
|
||||
*/
|
||||
public SipHashResult hash(byte[] data) {
|
||||
SipHashDigest digest = new SipHashDigest(v0, v1, v2, v3, c, d);
|
||||
|
||||
for (byte aData : data) {
|
||||
digest.update(aData);
|
||||
}
|
||||
|
||||
return digest.finish();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
/**
|
||||
* A basic enum to determine the case of a String.
|
||||
*
|
||||
* A String can either be UPPER or LOWER case.
|
||||
*/
|
||||
public enum SipHashCase { UPPER, LOWER }
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
/**
|
||||
* Class containing several constants for use alongside
|
||||
* hashing. Fields such as initial states and defaults,
|
||||
* as they will not change throughout hashing.
|
||||
*/
|
||||
class SipHashConstants {
|
||||
|
||||
/**
|
||||
* This constructor is private, nobody should be
|
||||
* accessing it!
|
||||
*
|
||||
* @throws IllegalAccessException
|
||||
*/
|
||||
private SipHashConstants() throws IllegalAccessException {
|
||||
throw new IllegalAccessException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial magic number for v0.
|
||||
*/
|
||||
static final long INITIAL_V0 = 0x736f6d6570736575L;
|
||||
|
||||
/**
|
||||
* Initial magic number for v1.
|
||||
*/
|
||||
static final long INITIAL_V1 = 0x646f72616e646f6dL;
|
||||
|
||||
/**
|
||||
* Initial magic number for v2.
|
||||
*/
|
||||
static final long INITIAL_V2 = 0x6c7967656e657261L;
|
||||
|
||||
/**
|
||||
* Initial magic number for v3.
|
||||
*/
|
||||
static final long INITIAL_V3 = 0x7465646279746573L;
|
||||
|
||||
/**
|
||||
* The default number of rounds of compression during per block.
|
||||
* This defaults to 2 as the default implementation is SipHash-2-4.
|
||||
*/
|
||||
static final int DEFAULT_C = 2;
|
||||
|
||||
/**
|
||||
* The default number of rounds of compression during finalization.
|
||||
* This defaults to 4 as the default implementation is SipHash-2-4.
|
||||
*/
|
||||
static final int DEFAULT_D = 4;
|
||||
|
||||
/**
|
||||
* Whether or not we should pad any hashes by default.
|
||||
*/
|
||||
static final boolean DEFAULT_PADDING = false;
|
||||
|
||||
/**
|
||||
* The default String casing for any output Hex Strings. We default
|
||||
* to lower case as it's the least expensive path.
|
||||
*/
|
||||
static final SipHashCase DEFAULT_CASE = SipHashCase.LOWER;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
import static com.zackehh.siphash.SipHashConstants.DEFAULT_C;
|
||||
import static com.zackehh.siphash.SipHashConstants.DEFAULT_D;
|
||||
|
||||
/**
|
||||
* A streaming implementation of SipHash, to be used when
|
||||
* you don't have all input available at the same time. Chunks
|
||||
* of bytes can be applied as they're received, and will be hashed
|
||||
* accordingly.
|
||||
*
|
||||
* As with ${@link SipHash}, the compression and finalization rounds
|
||||
* can be customized.
|
||||
*/
|
||||
public class SipHashDigest {
|
||||
|
||||
/**
|
||||
* The values of SipHash-c-d, to determine which of the SipHash
|
||||
* family we're using for this hash.
|
||||
*/
|
||||
private final int c, d;
|
||||
|
||||
/**
|
||||
* Initial seeded value of v0.
|
||||
*/
|
||||
private long v0;
|
||||
|
||||
/**
|
||||
* Initial seeded value of v1.
|
||||
*/
|
||||
private long v1;
|
||||
|
||||
/**
|
||||
* Initial seeded value of v2.
|
||||
*/
|
||||
private long v2;
|
||||
|
||||
/**
|
||||
* Initial seeded value of v3.
|
||||
*/
|
||||
private long v3;
|
||||
|
||||
/**
|
||||
* A counter to keep track of the length of the input.
|
||||
*/
|
||||
private byte input_len = 0;
|
||||
|
||||
/**
|
||||
* A counter to keep track of the current position inside
|
||||
* of a chunk of bytes. Seeing as bytes are applied in chunks
|
||||
* of 8, this is necessary.
|
||||
*/
|
||||
private int m_idx = 0;
|
||||
|
||||
/**
|
||||
* The `m` value from the SipHash algorithm. Every 8 bytes, this
|
||||
* value will be applied to the current state of the hash.
|
||||
*/
|
||||
private long m;
|
||||
|
||||
/**
|
||||
* Accepts a 16 byte key input, and uses it to initialize
|
||||
* the state of the hash. This uses the default values of
|
||||
* c/d, meaning that we default to SipHash-2-4.
|
||||
*
|
||||
* @param key a 16 byte key input
|
||||
*/
|
||||
public SipHashDigest(byte[] key) {
|
||||
this(key, DEFAULT_C, DEFAULT_D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a 16 byte key input, and uses it to initialize
|
||||
* the state of the hash. This constructor allows for
|
||||
* providing the c/d values, allowing the developer to
|
||||
* select any of the SipHash family to use for hashing.
|
||||
*
|
||||
* @param key a 16 byte key input
|
||||
* @param c the number of compression rounds
|
||||
* @param d the number of finalization rounds
|
||||
*/
|
||||
public SipHashDigest(byte[] key, int c, int d) {
|
||||
this.c = c;
|
||||
this.d = d;
|
||||
|
||||
SipHashKey hashKey = new SipHashKey(key);
|
||||
|
||||
this.v0 = SipHashConstants.INITIAL_V0 ^ hashKey.k0;
|
||||
this.v1 = SipHashConstants.INITIAL_V1 ^ hashKey.k1;
|
||||
this.v2 = SipHashConstants.INITIAL_V2 ^ hashKey.k0;
|
||||
this.v3 = SipHashConstants.INITIAL_V3 ^ hashKey.k1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor is used by the ${@link SipHash} implementation,
|
||||
* and takes an initial (seeded) value of v0/v1/v2/v3. This is used
|
||||
* when the key has been pre-calculated. This constructor also
|
||||
* receives the values of `c` and `d` to use in this hash.
|
||||
*
|
||||
* @param v0 an initial seeded v0
|
||||
* @param v1 an initial seeded v1
|
||||
* @param v2 an initial seeded v2
|
||||
* @param v3 an initial seeded v3
|
||||
* @param c the number of compression rounds
|
||||
* @param d the number of finalization rounds
|
||||
*/
|
||||
SipHashDigest(long v0, long v1, long v2, long v3, int c, int d) {
|
||||
this.c = c;
|
||||
this.d = d;
|
||||
|
||||
this.v0 = v0;
|
||||
this.v1 = v1;
|
||||
this.v2 = v2;
|
||||
this.v3 = v3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current state of the hash with a single byte. This
|
||||
* is the streaming implementation which shifts as required to ensure
|
||||
* we can take an arbitrary number of bytes at any given time. We only
|
||||
* apply the block once the index (`m_idx`) has reached 8. The number
|
||||
* of compression rounds is determined by the `c` value passed in by
|
||||
* the developer.
|
||||
*
|
||||
* This method returns this instance, as a way of allowing the developer
|
||||
* to chain.
|
||||
*
|
||||
* @return a ${@link SipHashDigest} instance
|
||||
*/
|
||||
public SipHashDigest update(byte b) {
|
||||
input_len++;
|
||||
m |= (((long) b & 0xff) << (m_idx * 8));
|
||||
m_idx++;
|
||||
if (m_idx >= 8) {
|
||||
v3 ^= m;
|
||||
for (int i = 0; i < c; i++) {
|
||||
round();
|
||||
}
|
||||
v0 ^= m;
|
||||
m_idx = 0;
|
||||
m = 0;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method to allow passing a chunk of bytes at once, rather
|
||||
* than a byte at a time.
|
||||
*
|
||||
* @return a ${@link SipHashDigest} instance
|
||||
*/
|
||||
public SipHashDigest update(byte[] bytes) {
|
||||
for (byte b : bytes) {
|
||||
update(b);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes the hash by padding 0s until the next multiple of
|
||||
* 8 (as we operate in 8 byte chunks). The last byte added to
|
||||
* the hash is the length of the input, which we keep inside the
|
||||
* `input_len` counter. The number of rounds is based on the value
|
||||
* of `d` as specified by the developer.
|
||||
*
|
||||
* This method returns a ${@link SipHashResult}, as no further updates
|
||||
* should occur (i.e. the lack of chaining here shows we're done).
|
||||
*
|
||||
* @return a ${@link SipHashResult} instance
|
||||
*/
|
||||
public SipHashResult finish() {
|
||||
byte msgLenMod256 = input_len;
|
||||
|
||||
while (m_idx < 7) {
|
||||
update((byte) 0);
|
||||
}
|
||||
update(msgLenMod256);
|
||||
|
||||
v2 ^= 0xff;
|
||||
for (int i = 0; i < d; i++) {
|
||||
round();
|
||||
}
|
||||
|
||||
return new SipHashResult(v0 ^ v1 ^ v2 ^ v3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the equivalent of SipRound on the provided state.
|
||||
* This method affects the state of this digest, in that it
|
||||
* mutates the v states directly.
|
||||
*/
|
||||
private void round() {
|
||||
v0 += v1;
|
||||
v2 += v3;
|
||||
v1 = rotateLeft(v1, 13);
|
||||
v3 = rotateLeft(v3, 16);
|
||||
|
||||
v1 ^= v0;
|
||||
v3 ^= v2;
|
||||
v0 = rotateLeft(v0, 32);
|
||||
|
||||
v2 += v1;
|
||||
v0 += v3;
|
||||
v1 = rotateLeft(v1, 17);
|
||||
v3 = rotateLeft(v3, 21);
|
||||
|
||||
v1 ^= v2;
|
||||
v3 ^= v0;
|
||||
v2 = rotateLeft(v2, 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates an input number `val` left by `shift` number of bits. Bits which are
|
||||
* pushed off to the left are rotated back onto the right, making this a left
|
||||
* rotation (a circular shift).
|
||||
*
|
||||
* @param val the value to be shifted
|
||||
* @param shift how far left to shift
|
||||
* @return a long value once shifted
|
||||
*/
|
||||
private long rotateLeft(long val, int shift) {
|
||||
return (val << shift) | val >>> (64 - shift);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
/**
|
||||
* A container class to store both k0 and k1. These
|
||||
* values are created from a 16 byte key passed into
|
||||
* the constructor. This isn't ideal as it's another
|
||||
* alloc, but it'll do for now.
|
||||
*/
|
||||
class SipHashKey {
|
||||
|
||||
/**
|
||||
* The value of k0.
|
||||
*/
|
||||
final long k0;
|
||||
|
||||
/**
|
||||
* The value of k1.
|
||||
*/
|
||||
final long k1;
|
||||
|
||||
/**
|
||||
* Accepts a 16 byte input key and converts the
|
||||
* first and last 8 byte chunks to little-endian.
|
||||
* These values become k0 and k1.
|
||||
*
|
||||
* @param key the 16 byte key input
|
||||
*/
|
||||
public SipHashKey(byte[] key) {
|
||||
if (key.length != 16) {
|
||||
throw new IllegalArgumentException("Key must be exactly 16 bytes!");
|
||||
}
|
||||
this.k0 = bytesToLong(key, 0);
|
||||
this.k1 = bytesToLong(key, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a chunk of 8 bytes to a number in little-endian
|
||||
* format. Accepts an offset to determine where the chunk
|
||||
* begins in the byte array.
|
||||
*
|
||||
* @param b our byte array
|
||||
* @param offset the index to start at
|
||||
* @return a little-endian long representation
|
||||
*/
|
||||
private static long bytesToLong(byte[] b, int offset) {
|
||||
long m = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
m |= ((((long) b[i + offset]) & 0xff) << (8 * i));
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
import static com.zackehh.siphash.SipHashConstants.DEFAULT_CASE;
|
||||
import static com.zackehh.siphash.SipHashConstants.DEFAULT_PADDING;
|
||||
|
||||
/**
|
||||
* A container class of the result of a hash. This class exists
|
||||
* to allow the developer to retrieve the result in any format
|
||||
* they like. Currently available formats are `long` and ${@link java.lang.String}.
|
||||
* When retrieving as a String, the developer can specify the case
|
||||
* they want it in, and whether or not we should pad the left side
|
||||
* to 16 characters with 0s.
|
||||
*/
|
||||
public class SipHashResult {
|
||||
|
||||
/**
|
||||
* The internal hash result.
|
||||
*/
|
||||
private final long result;
|
||||
|
||||
/**
|
||||
* A package-private constructor, as only
|
||||
* SipHash should be creating results.
|
||||
*
|
||||
* @param result the result of a hash
|
||||
*/
|
||||
SipHashResult(long result){
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply returns the hash result as a long.
|
||||
*
|
||||
* @return the hash value as a long
|
||||
*/
|
||||
public long get(){
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result as a Hex String, using
|
||||
* the default padding and casing values.
|
||||
*
|
||||
* @return the hash value as a Hex String
|
||||
*/
|
||||
public String getHex(){
|
||||
return getHex(DEFAULT_PADDING, DEFAULT_CASE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result as a Hex String, using
|
||||
* a custom padding value and default casing value.
|
||||
*
|
||||
* @param padding whether or not to pad the string
|
||||
* @return the hash value as a Hex String
|
||||
*/
|
||||
public String getHex(boolean padding){
|
||||
return getHex(padding, DEFAULT_CASE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result as a Hex String, using
|
||||
* a default padding value and custom casing value.
|
||||
*
|
||||
* @param s_case the case to convert the output to
|
||||
* @return the hash value as a Hex String
|
||||
*/
|
||||
public String getHex(SipHashCase s_case){
|
||||
return getHex(DEFAULT_PADDING, s_case);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result as a Hex String, taking in
|
||||
* various arguments to customize the output further,
|
||||
* such as casing and padding.
|
||||
*
|
||||
* @param padding whether or not to pad the string
|
||||
* @param s_case the case to convert the output to
|
||||
* @return a Hex String in the custom format
|
||||
*/
|
||||
public String getHex(boolean padding, SipHashCase s_case){
|
||||
String str = Long.toHexString(get());
|
||||
if (padding) {
|
||||
str = leftPad(str, 16, "0");
|
||||
}
|
||||
if (s_case == SipHashCase.UPPER) {
|
||||
str = str.toUpperCase();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modified for https://github.com/Zukero/ATCS
|
||||
* Replaces the StringUtils.leftPad from apache commons, to remove dependency.
|
||||
*
|
||||
* @param str the string to pad
|
||||
* @param len the total desired length
|
||||
* @param pad the padding string
|
||||
* @return str prefixed with enough repetitions of the pad to have a total length matching len
|
||||
*/
|
||||
public String leftPad(String str, int len, String pad) {
|
||||
StringBuilder sb = new StringBuilder(len);
|
||||
|
||||
int padlen = len - str.length();
|
||||
int partialPadLen = padlen % pad.length();
|
||||
int padCount = padlen / pad.length();
|
||||
|
||||
while (padCount >= 0) {
|
||||
sb.append(pad);
|
||||
padCount--;
|
||||
}
|
||||
|
||||
if (partialPadLen > 0) {
|
||||
sb.append(pad.substring(0, partialPadLen));
|
||||
}
|
||||
|
||||
sb.append(str);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class SipHashCaseTest {
|
||||
|
||||
@Test
|
||||
public void ensureAllValues() throws Exception {
|
||||
SipHashCase[] cases = SipHashCase.values();
|
||||
|
||||
Assert.assertEquals(cases[0], SipHashCase.UPPER);
|
||||
Assert.assertEquals(cases[1], SipHashCase.LOWER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensureValueOf() throws Exception {
|
||||
Assert.assertEquals(SipHashCase.valueOf("UPPER"), SipHashCase.UPPER);
|
||||
Assert.assertEquals(SipHashCase.valueOf("LOWER"), SipHashCase.LOWER);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void invalidCaseValueOf() throws Exception {
|
||||
SipHashCase.valueOf("invalid");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
public class SipHashConstantsTest {
|
||||
|
||||
@Test
|
||||
public void ensureAllConstants() throws Exception {
|
||||
Assert.assertEquals(SipHashConstants.INITIAL_V0, 0x736f6d6570736575L);
|
||||
Assert.assertEquals(SipHashConstants.INITIAL_V1, 0x646f72616e646f6dL);
|
||||
Assert.assertEquals(SipHashConstants.INITIAL_V2, 0x6c7967656e657261L);
|
||||
Assert.assertEquals(SipHashConstants.INITIAL_V3, 0x7465646279746573L);
|
||||
Assert.assertEquals(SipHashConstants.DEFAULT_C, 2);
|
||||
Assert.assertEquals(SipHashConstants.DEFAULT_D, 4);
|
||||
Assert.assertEquals(SipHashConstants.DEFAULT_CASE, SipHashCase.LOWER);
|
||||
Assert.assertEquals(SipHashConstants.DEFAULT_PADDING, false);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = InvocationTargetException.class)
|
||||
public void ensureCannotInstance() throws Exception {
|
||||
Constructor<SipHashConstants> ctor = SipHashConstants.class.getDeclaredConstructor();
|
||||
ctor.setAccessible(true);
|
||||
Assert.assertTrue(Modifier.isPrivate(ctor.getModifiers()));
|
||||
ctor.newInstance();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class SipHashDigestTest {
|
||||
|
||||
@Test
|
||||
public void initializeDigestWithKey() throws Exception {
|
||||
SipHashDigest sipHash = new SipHashDigest("0123456789ABCDEF".getBytes());
|
||||
|
||||
long v0 = SipHashTestUtils.getPrivateField(sipHash, "v0", Long.class);
|
||||
long v1 = SipHashTestUtils.getPrivateField(sipHash, "v1", Long.class);
|
||||
long v2 = SipHashTestUtils.getPrivateField(sipHash, "v2", Long.class);
|
||||
long v3 = SipHashTestUtils.getPrivateField(sipHash, "v3", Long.class);
|
||||
|
||||
Assert.assertEquals(v0, 4925064773550298181L);
|
||||
Assert.assertEquals(v1, 2461839666708829781L);
|
||||
Assert.assertEquals(v2, 6579568090023412561L);
|
||||
Assert.assertEquals(v3, 3611922228250500171L);
|
||||
|
||||
int c = SipHashTestUtils.getPrivateField(sipHash, "c", Integer.class);
|
||||
int d = SipHashTestUtils.getPrivateField(sipHash, "d", Integer.class);
|
||||
|
||||
Assert.assertEquals(c, SipHashConstants.DEFAULT_C);
|
||||
Assert.assertEquals(d, SipHashConstants.DEFAULT_D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initializeDigestWithKeyAndCD() throws Exception {
|
||||
SipHashDigest sipHash = new SipHashDigest("0123456789ABCDEF".getBytes(), 4, 8);
|
||||
|
||||
long v0 = SipHashTestUtils.getPrivateField(sipHash, "v0", Long.class);
|
||||
long v1 = SipHashTestUtils.getPrivateField(sipHash, "v1", Long.class);
|
||||
long v2 = SipHashTestUtils.getPrivateField(sipHash, "v2", Long.class);
|
||||
long v3 = SipHashTestUtils.getPrivateField(sipHash, "v3", Long.class);
|
||||
|
||||
Assert.assertEquals(v0, 4925064773550298181L);
|
||||
Assert.assertEquals(v1, 2461839666708829781L);
|
||||
Assert.assertEquals(v2, 6579568090023412561L);
|
||||
Assert.assertEquals(v3, 3611922228250500171L);
|
||||
|
||||
int c = SipHashTestUtils.getPrivateField(sipHash, "c", Integer.class);
|
||||
int d = SipHashTestUtils.getPrivateField(sipHash, "d", Integer.class);
|
||||
|
||||
Assert.assertEquals(c, 4);
|
||||
Assert.assertEquals(d, 8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initializeDigestWithKeyThenHash() throws Exception {
|
||||
SipHashDigest sipHash = new SipHashDigest("0123456789ABCDEF".getBytes());
|
||||
|
||||
long v0 = SipHashTestUtils.getPrivateField(sipHash, "v0", Long.class);
|
||||
long v1 = SipHashTestUtils.getPrivateField(sipHash, "v1", Long.class);
|
||||
long v2 = SipHashTestUtils.getPrivateField(sipHash, "v2", Long.class);
|
||||
long v3 = SipHashTestUtils.getPrivateField(sipHash, "v3", Long.class);
|
||||
|
||||
Assert.assertEquals(v0, 4925064773550298181L);
|
||||
Assert.assertEquals(v1, 2461839666708829781L);
|
||||
Assert.assertEquals(v2, 6579568090023412561L);
|
||||
Assert.assertEquals(v3, 3611922228250500171L);
|
||||
|
||||
int c = SipHashTestUtils.getPrivateField(sipHash, "c", Integer.class);
|
||||
int d = SipHashTestUtils.getPrivateField(sipHash, "d", Integer.class);
|
||||
|
||||
Assert.assertEquals(c, SipHashConstants.DEFAULT_C);
|
||||
Assert.assertEquals(d, SipHashConstants.DEFAULT_D);
|
||||
|
||||
for(byte b : "zymotechnics".getBytes()){
|
||||
sipHash.update(b);
|
||||
}
|
||||
|
||||
SipHashResult hashResult = sipHash.finish();
|
||||
|
||||
Assert.assertEquals(hashResult.get(), 699588702094987020L);
|
||||
Assert.assertEquals(hashResult.getHex(), "9b57037cd3f8f0c");
|
||||
Assert.assertEquals(hashResult.getHex(true), "09b57037cd3f8f0c");
|
||||
Assert.assertEquals(hashResult.getHex(SipHashCase.UPPER), "9B57037CD3F8F0C");
|
||||
Assert.assertEquals(hashResult.getHex(true, SipHashCase.UPPER), "09B57037CD3F8F0C");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initializeStateWithKeyAndCDThenHash() throws Exception {
|
||||
SipHashDigest sipHash = new SipHashDigest("0123456789ABCDEF".getBytes(), 4, 8);
|
||||
|
||||
long v0 = SipHashTestUtils.getPrivateField(sipHash, "v0", Long.class);
|
||||
long v1 = SipHashTestUtils.getPrivateField(sipHash, "v1", Long.class);
|
||||
long v2 = SipHashTestUtils.getPrivateField(sipHash, "v2", Long.class);
|
||||
long v3 = SipHashTestUtils.getPrivateField(sipHash, "v3", Long.class);
|
||||
|
||||
Assert.assertEquals(v0, 4925064773550298181L);
|
||||
Assert.assertEquals(v1, 2461839666708829781L);
|
||||
Assert.assertEquals(v2, 6579568090023412561L);
|
||||
Assert.assertEquals(v3, 3611922228250500171L);
|
||||
|
||||
int c = SipHashTestUtils.getPrivateField(sipHash, "c", Integer.class);
|
||||
int d = SipHashTestUtils.getPrivateField(sipHash, "d", Integer.class);
|
||||
|
||||
Assert.assertEquals(c, 4);
|
||||
Assert.assertEquals(d, 8);
|
||||
|
||||
for(byte b : "zymotechnics".getBytes()){
|
||||
sipHash.update(b);
|
||||
}
|
||||
|
||||
SipHashResult hashResult = sipHash.finish();
|
||||
|
||||
Assert.assertEquals(hashResult.get(), -3891084581787974112L); // overflow
|
||||
Assert.assertEquals(hashResult.getHex(), "ca0017304f874620");
|
||||
Assert.assertEquals(hashResult.getHex(true), "ca0017304f874620");
|
||||
Assert.assertEquals(hashResult.getHex(SipHashCase.UPPER), "CA0017304F874620");
|
||||
Assert.assertEquals(hashResult.getHex(true, SipHashCase.UPPER), "CA0017304F874620");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateWithAByteArrayChunk() throws Exception {
|
||||
SipHashDigest sipHash = new SipHashDigest("0123456789ABCDEF".getBytes());
|
||||
|
||||
long v0 = SipHashTestUtils.getPrivateField(sipHash, "v0", Long.class);
|
||||
long v1 = SipHashTestUtils.getPrivateField(sipHash, "v1", Long.class);
|
||||
long v2 = SipHashTestUtils.getPrivateField(sipHash, "v2", Long.class);
|
||||
long v3 = SipHashTestUtils.getPrivateField(sipHash, "v3", Long.class);
|
||||
|
||||
Assert.assertEquals(v0, 4925064773550298181L);
|
||||
Assert.assertEquals(v1, 2461839666708829781L);
|
||||
Assert.assertEquals(v2, 6579568090023412561L);
|
||||
Assert.assertEquals(v3, 3611922228250500171L);
|
||||
|
||||
int c = SipHashTestUtils.getPrivateField(sipHash, "c", Integer.class);
|
||||
int d = SipHashTestUtils.getPrivateField(sipHash, "d", Integer.class);
|
||||
|
||||
Assert.assertEquals(c, SipHashConstants.DEFAULT_C);
|
||||
Assert.assertEquals(d, SipHashConstants.DEFAULT_D);
|
||||
|
||||
sipHash.update("zymo".getBytes());
|
||||
sipHash.update("techni".getBytes());
|
||||
sipHash.update("cs".getBytes());
|
||||
|
||||
SipHashResult hashResult = sipHash.finish();
|
||||
|
||||
Assert.assertEquals(hashResult.get(), 699588702094987020L);
|
||||
Assert.assertEquals(hashResult.getHex(), "9b57037cd3f8f0c");
|
||||
Assert.assertEquals(hashResult.getHex(true), "09b57037cd3f8f0c");
|
||||
Assert.assertEquals(hashResult.getHex(SipHashCase.UPPER), "9B57037CD3F8F0C");
|
||||
Assert.assertEquals(hashResult.getHex(true, SipHashCase.UPPER), "09B57037CD3F8F0C");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class SipHashKeyTest {
|
||||
|
||||
@Test
|
||||
public void initializeWithKey() throws Exception {
|
||||
SipHashKey key = new SipHashKey("0123456789ABCDEF".getBytes());
|
||||
|
||||
long k0 = SipHashTestUtils.getPrivateField(key, "k0", Long.class);
|
||||
long k1 = SipHashTestUtils.getPrivateField(key, "k1", Long.class);
|
||||
|
||||
Assert.assertEquals(k0, 3978425819141910832L);
|
||||
Assert.assertEquals(k1, 5063528411713059128L);
|
||||
}
|
||||
|
||||
@Test(
|
||||
expectedExceptions = IllegalArgumentException.class,
|
||||
expectedExceptionsMessageRegExp = "Key must be exactly 16 bytes!"
|
||||
)
|
||||
public void initializeWithKeyTooLong() throws Exception {
|
||||
new SipHashKey("0123456789ABCDEFG".getBytes()); // 17 bytes
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class SipHashTest {
|
||||
|
||||
@Test
|
||||
public void initializeStateWithKey() throws Exception {
|
||||
SipHash sipHash = new SipHash("0123456789ABCDEF".getBytes());
|
||||
|
||||
long v0 = SipHashTestUtils.getPrivateField(sipHash, "v0", Long.class);
|
||||
long v1 = SipHashTestUtils.getPrivateField(sipHash, "v1", Long.class);
|
||||
long v2 = SipHashTestUtils.getPrivateField(sipHash, "v2", Long.class);
|
||||
long v3 = SipHashTestUtils.getPrivateField(sipHash, "v3", Long.class);
|
||||
|
||||
Assert.assertEquals(v0, 4925064773550298181L);
|
||||
Assert.assertEquals(v1, 2461839666708829781L);
|
||||
Assert.assertEquals(v2, 6579568090023412561L);
|
||||
Assert.assertEquals(v3, 3611922228250500171L);
|
||||
|
||||
int c = SipHashTestUtils.getPrivateField(sipHash, "c", Integer.class);
|
||||
int d = SipHashTestUtils.getPrivateField(sipHash, "d", Integer.class);
|
||||
|
||||
Assert.assertEquals(c, SipHashConstants.DEFAULT_C);
|
||||
Assert.assertEquals(d, SipHashConstants.DEFAULT_D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initializeStateWithKeyAndCD() throws Exception {
|
||||
SipHash sipHash = new SipHash("0123456789ABCDEF".getBytes(), 4, 8);
|
||||
|
||||
long v0 = SipHashTestUtils.getPrivateField(sipHash, "v0", Long.class);
|
||||
long v1 = SipHashTestUtils.getPrivateField(sipHash, "v1", Long.class);
|
||||
long v2 = SipHashTestUtils.getPrivateField(sipHash, "v2", Long.class);
|
||||
long v3 = SipHashTestUtils.getPrivateField(sipHash, "v3", Long.class);
|
||||
|
||||
Assert.assertEquals(v0, 4925064773550298181L);
|
||||
Assert.assertEquals(v1, 2461839666708829781L);
|
||||
Assert.assertEquals(v2, 6579568090023412561L);
|
||||
Assert.assertEquals(v3, 3611922228250500171L);
|
||||
|
||||
int c = SipHashTestUtils.getPrivateField(sipHash, "c", Integer.class);
|
||||
int d = SipHashTestUtils.getPrivateField(sipHash, "d", Integer.class);
|
||||
|
||||
Assert.assertEquals(c, 4);
|
||||
Assert.assertEquals(d, 8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initializeStateWithKeyThenHash() throws Exception {
|
||||
SipHash sipHash = new SipHash("0123456789ABCDEF".getBytes());
|
||||
|
||||
long v0 = SipHashTestUtils.getPrivateField(sipHash, "v0", Long.class);
|
||||
long v1 = SipHashTestUtils.getPrivateField(sipHash, "v1", Long.class);
|
||||
long v2 = SipHashTestUtils.getPrivateField(sipHash, "v2", Long.class);
|
||||
long v3 = SipHashTestUtils.getPrivateField(sipHash, "v3", Long.class);
|
||||
|
||||
Assert.assertEquals(v0, 4925064773550298181L);
|
||||
Assert.assertEquals(v1, 2461839666708829781L);
|
||||
Assert.assertEquals(v2, 6579568090023412561L);
|
||||
Assert.assertEquals(v3, 3611922228250500171L);
|
||||
|
||||
int c = SipHashTestUtils.getPrivateField(sipHash, "c", Integer.class);
|
||||
int d = SipHashTestUtils.getPrivateField(sipHash, "d", Integer.class);
|
||||
|
||||
Assert.assertEquals(c, SipHashConstants.DEFAULT_C);
|
||||
Assert.assertEquals(d, SipHashConstants.DEFAULT_D);
|
||||
|
||||
SipHashResult hashResult = sipHash.hash("zymotechnics".getBytes());
|
||||
|
||||
Assert.assertEquals(hashResult.get(), 699588702094987020L);
|
||||
Assert.assertEquals(hashResult.getHex(), "9b57037cd3f8f0c");
|
||||
Assert.assertEquals(hashResult.getHex(true), "09b57037cd3f8f0c");
|
||||
Assert.assertEquals(hashResult.getHex(SipHashCase.UPPER), "9B57037CD3F8F0C");
|
||||
Assert.assertEquals(hashResult.getHex(true, SipHashCase.UPPER), "09B57037CD3F8F0C");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initializeStateWithKeyAndCDThenHash() throws Exception {
|
||||
SipHash sipHash = new SipHash("0123456789ABCDEF".getBytes(), 4, 8);
|
||||
|
||||
long v0 = SipHashTestUtils.getPrivateField(sipHash, "v0", Long.class);
|
||||
long v1 = SipHashTestUtils.getPrivateField(sipHash, "v1", Long.class);
|
||||
long v2 = SipHashTestUtils.getPrivateField(sipHash, "v2", Long.class);
|
||||
long v3 = SipHashTestUtils.getPrivateField(sipHash, "v3", Long.class);
|
||||
|
||||
Assert.assertEquals(v0, 4925064773550298181L);
|
||||
Assert.assertEquals(v1, 2461839666708829781L);
|
||||
Assert.assertEquals(v2, 6579568090023412561L);
|
||||
Assert.assertEquals(v3, 3611922228250500171L);
|
||||
|
||||
int c = SipHashTestUtils.getPrivateField(sipHash, "c", Integer.class);
|
||||
int d = SipHashTestUtils.getPrivateField(sipHash, "d", Integer.class);
|
||||
|
||||
Assert.assertEquals(c, 4);
|
||||
Assert.assertEquals(d, 8);
|
||||
|
||||
SipHashResult hashResult = sipHash.hash("zymotechnics".getBytes());
|
||||
|
||||
Assert.assertEquals(hashResult.get(), -3891084581787974112L); // overflow
|
||||
Assert.assertEquals(hashResult.getHex(), "ca0017304f874620");
|
||||
Assert.assertEquals(hashResult.getHex(true), "ca0017304f874620");
|
||||
Assert.assertEquals(hashResult.getHex(SipHashCase.UPPER), "CA0017304F874620");
|
||||
Assert.assertEquals(hashResult.getHex(true, SipHashCase.UPPER), "CA0017304F874620");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.zackehh.siphash;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class SipHashTestUtils {
|
||||
|
||||
static <T> T getPrivateField(Object obj, String name, Class<T> clazz) throws Exception {
|
||||
Field f = obj.getClass().getDeclaredField(name);
|
||||
f.setAccessible(true);
|
||||
return clazz.cast(f.get(obj));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +1,53 @@
|
||||
package com.gpl.rpg.atcontentstudio;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import javax.swing.event.HyperlinkListener;
|
||||
|
||||
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 {
|
||||
|
||||
public static final String APP_NAME = "Andor's Trail Content Studio";
|
||||
public static final String APP_VERSION = "v0.4.3";
|
||||
public static final String APP_VERSION = "v0.6.5";
|
||||
|
||||
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";
|
||||
|
||||
public static boolean STARTED = false;
|
||||
public static StudioFrame frame = null;
|
||||
|
||||
//Need to keep a strong reference to it, to avoid garbage collection that'll reset these loggers.
|
||||
public static final List<Logger> configuredLoggers = new LinkedList<Logger>();
|
||||
|
||||
/**
|
||||
* @param args
|
||||
@@ -44,6 +70,10 @@ public class ATContentStudio {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//Need to keep a strong reference to it, to avoid garbage collection that'll reset this setting.
|
||||
Logger l = Logger.getLogger(ExpressionParser.class.getName());
|
||||
l.setLevel(Level.OFF);
|
||||
configuredLoggers.add(l);
|
||||
|
||||
final WorkspaceSelector wsSelect = new WorkspaceSelector();
|
||||
wsSelect.pack();
|
||||
@@ -61,9 +91,14 @@ public class ATContentStudio {
|
||||
WorkerDialog.showTaskMessage("Loading your workspace...", null, new Runnable(){
|
||||
public void run() {
|
||||
Workspace.setActive(workspaceRoot);
|
||||
if (Workspace.activeWorkspace.settings.useInternet.getCurrentValue() && Workspace.activeWorkspace.settings.checkUpdates.getCurrentValue()) {
|
||||
new Thread() {
|
||||
public void run() {checkUpdate();}
|
||||
}.start();
|
||||
}
|
||||
frame = new StudioFrame(APP_NAME+" "+APP_VERSION);
|
||||
frame.setVisible(true);
|
||||
frame.setDefaultCloseOperation(StudioFrame.EXIT_ON_CLOSE);
|
||||
frame.setDefaultCloseOperation(StudioFrame.DO_NOTHING_ON_CLOSE);
|
||||
};
|
||||
});
|
||||
for (File f : ConfigCache.getKnownWorkspaces()) {
|
||||
@@ -82,4 +117,65 @@ public class ATContentStudio {
|
||||
});
|
||||
}
|
||||
|
||||
private static void checkUpdate() {
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
URL url = new URL(CHECK_UPDATE_URL);
|
||||
in = new BufferedReader(new InputStreamReader(url.openStream()));
|
||||
|
||||
String inputLine, lastLine = null;
|
||||
while ((inputLine = in.readLine()) != null) {lastLine = inputLine;}
|
||||
if (lastLine != null && !lastLine.equals(APP_VERSION)) {
|
||||
|
||||
// for copying style
|
||||
JLabel label = new JLabel();
|
||||
Font font = label.getFont();
|
||||
Color color = label.getBackground();
|
||||
|
||||
// create some css from the label's font
|
||||
StringBuffer style = new StringBuffer("font-family:" + font.getFamily() + ";");
|
||||
style.append("font-weight:" + (font.isBold() ? "bold" : "normal") + ";");
|
||||
style.append("font-size:" + font.getSize() + "pt;");
|
||||
style.append("background-color: rgb("+color.getRed()+","+color.getGreen()+","+color.getBlue()+");");
|
||||
|
||||
JEditorPane ep = new JEditorPane("text/html", "<html><body style=\"" + style + "\">"
|
||||
+ "You are not running the latest ATCS version.<br/>"
|
||||
+ "You can get the latest version ("+lastLine+") by clicking the link below.<br/>"
|
||||
+ "<a href=\""+DOWNLOAD_URL+"\">"+DOWNLOAD_URL+"</a><br/>"
|
||||
+ "<br/>"
|
||||
+ "</body></html>");
|
||||
|
||||
ep.setEditable(false);
|
||||
ep.setBorder(null);
|
||||
|
||||
ep.addHyperlinkListener(new HyperlinkListener() {
|
||||
|
||||
@Override
|
||||
public void hyperlinkUpdate(HyperlinkEvent e) {
|
||||
try {
|
||||
if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
|
||||
Desktop.getDesktop().browse(e.getURL().toURI());
|
||||
}
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (URISyntaxException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JOptionPane.showMessageDialog(null, ep, "Update available", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (in != null) in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ package com.gpl.rpg.atcontentstudio;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public class Notification {
|
||||
|
||||
public static List<Notification> notifs = new ArrayList<Notification>();
|
||||
private static List<NotificationListener> listeners = new ArrayList<NotificationListener>();
|
||||
private static List<NotificationListener> listeners = new CopyOnWriteArrayList<NotificationListener>();
|
||||
public static boolean showS = true, showI = true, showW = true, showE = true;
|
||||
|
||||
static {
|
||||
|
||||
|
Before Width: | Height: | Size: 566 B |
|
Before Width: | Height: | Size: 278 B |
BIN
src/com/gpl/rpg/atcontentstudio/img/label.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/com/gpl/rpg/atcontentstudio/img/status_blue.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
src/com/gpl/rpg/atcontentstudio/img/status_green.png
Normal file
|
After Width: | Height: | Size: 1013 B |
BIN
src/com/gpl/rpg/atcontentstudio/img/status_orange.png
Normal file
|
After Width: | Height: | Size: 1023 B |
BIN
src/com/gpl/rpg/atcontentstudio/img/status_red.png
Normal file
|
After Width: | Height: | Size: 880 B |
BIN
src/com/gpl/rpg/atcontentstudio/img/status_unknown.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 481 B |
@@ -116,4 +116,9 @@ public class ClosedProject implements ProjectTreeNode {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import java.awt.Image;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
@@ -32,7 +32,7 @@ public abstract class GameDataElement implements ProjectTreeNode, Serializable {
|
||||
public boolean writable = false;
|
||||
|
||||
//List of objects whose transition to "linked" state made them point to this instance.
|
||||
private Map<GameDataElement, Integer> backlinks = new HashMap<GameDataElement, Integer>();
|
||||
private Map<GameDataElement, Integer> backlinks = new ConcurrentHashMap<GameDataElement, Integer>();
|
||||
|
||||
public String id = null;
|
||||
|
||||
@@ -99,7 +99,7 @@ public abstract class GameDataElement implements ProjectTreeNode, Serializable {
|
||||
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return parent.getProject();
|
||||
return parent == null ? null : parent.getProject();
|
||||
}
|
||||
|
||||
|
||||
@@ -176,6 +176,10 @@ public abstract class GameDataElement implements ProjectTreeNode, Serializable {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean needsSaving() {
|
||||
return this.state == State.modified || this.state == State.created;
|
||||
}
|
||||
|
||||
public abstract String getProjectFilename();
|
||||
|
||||
public abstract void save();
|
||||
|
||||
@@ -2,29 +2,49 @@ 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.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
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.model.Project.ResourceSet;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
|
||||
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.sprites.SpriteSheetSet;
|
||||
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
|
||||
import com.gpl.rpg.atcontentstudio.model.tools.writermode.WriterModeDataSet;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
|
||||
public class GameSource implements ProjectTreeNode, Serializable {
|
||||
|
||||
private static final long serialVersionUID = -1512979360971918158L;
|
||||
|
||||
public static final String DEFAULT_REL_PATH_FOR_GAME_RESOURCE = "res"+File.separator+"values"+File.separator+"loadresources.xml";
|
||||
public static final String DEFAULT_REL_PATH_FOR_DEBUG_RESOURCE = "res"+File.separator+"values"+File.separator+"loadresources_debug.xml";
|
||||
|
||||
public transient GameDataSet gameData;
|
||||
public transient TMXMapSet gameMaps;
|
||||
public transient SpriteSheetSet gameSprites;
|
||||
public transient Worldmap worldmap;
|
||||
public transient WriterModeDataSet writerModeDataSet;
|
||||
private transient SavedSlotCollection v;
|
||||
|
||||
public static enum Type {
|
||||
@@ -39,6 +59,8 @@ public class GameSource implements ProjectTreeNode, Serializable {
|
||||
|
||||
public transient Project parent = null;
|
||||
|
||||
public transient Map<String, List<String>> referencedSourceFiles = null;
|
||||
|
||||
public GameSource(File folder, Project parent) {
|
||||
this.parent = parent;
|
||||
this.baseFolder = folder;
|
||||
@@ -59,6 +81,15 @@ public class GameSource implements ProjectTreeNode, Serializable {
|
||||
}
|
||||
|
||||
public void initData() {
|
||||
if (type == Type.source) {
|
||||
if (parent.sourceSetToUse == ResourceSet.gameData || parent.sourceSetToUse == ResourceSet.debugData) {
|
||||
referencedSourceFiles = new LinkedHashMap<String, List<String>>();
|
||||
readResourceList();
|
||||
}
|
||||
}
|
||||
if (type == Type.created) {
|
||||
this.writerModeDataSet = new WriterModeDataSet(this);
|
||||
}
|
||||
this.gameData = new GameDataSet(this);
|
||||
this.gameMaps = new TMXMapSet(this);
|
||||
this.gameSprites = new SpriteSheetSet(this);
|
||||
@@ -68,6 +99,61 @@ public class GameSource implements ProjectTreeNode, Serializable {
|
||||
v.add(gameMaps);
|
||||
v.add(gameSprites);
|
||||
v.add(worldmap);
|
||||
if (type == Type.created) {
|
||||
v.add(writerModeDataSet);
|
||||
}
|
||||
}
|
||||
|
||||
public void readResourceList() {
|
||||
File xmlFile = null;
|
||||
if (parent.sourceSetToUse == ResourceSet.gameData) {
|
||||
xmlFile = new File(baseFolder, DEFAULT_REL_PATH_FOR_GAME_RESOURCE);
|
||||
} else if (parent.sourceSetToUse == ResourceSet.debugData) {
|
||||
xmlFile = new File(baseFolder, DEFAULT_REL_PATH_FOR_DEBUG_RESOURCE);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
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 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++) {
|
||||
Element arrayNode = (Element) arraysList.item(i);
|
||||
String name = arrayNode.getAttribute("name");
|
||||
List<String> arrayContents = new ArrayList<String>();
|
||||
NodeList arrayItems = arrayNode.getElementsByTagName("item");
|
||||
if (arrayItems != null) {
|
||||
for (int j = 0; j < arrayItems.getLength(); j++) {
|
||||
arrayContents.add(((Element)arrayItems.item(j)).getTextContent());
|
||||
}
|
||||
referencedSourceFiles.put(name, arrayContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SAXException e) {
|
||||
e.printStackTrace();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,11 +213,11 @@ public class GameSource implements ProjectTreeNode, Serializable {
|
||||
@Override
|
||||
public String getDesc() {
|
||||
switch(type) {
|
||||
case altered: return "Altered data";
|
||||
case created: return "Created data";
|
||||
case referenced: return "Referenced data";
|
||||
case source: return "AT Source"; //The fact that it is from "source" is already mentionned by its parent.
|
||||
default: return "Game data";
|
||||
case altered: return (needsSaving() ? "*" : "")+"Altered data";
|
||||
case created: return (needsSaving() ? "*" : "")+"Created data";
|
||||
case referenced: return (needsSaving() ? "*" : "")+"Referenced data";
|
||||
case source: return (needsSaving() ? "*" : "")+"AT Source"; //The fact that it is from "source" is already mentionned by its parent.
|
||||
default: return (needsSaving() ? "*" : "")+"Game data";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,4 +283,12 @@ public class GameSource implements ProjectTreeNode, Serializable {
|
||||
public WorldmapSegment getWorldmapSegment(String id) {
|
||||
return worldmap.getWorldmapSegment(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
for (ProjectTreeNode node : v.getNonEmptyIterable()) {
|
||||
if (node.needsSaving()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ 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;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
@@ -38,12 +39,14 @@ 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.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;
|
||||
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
|
||||
import com.gpl.rpg.atcontentstudio.model.tools.writermode.WriterModeData;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
import com.gpl.rpg.atcontentstudio.ui.WorkerDialog;
|
||||
import com.gpl.rpg.atcontentstudio.utils.FileUtils;
|
||||
@@ -73,10 +76,19 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
public transient Workspace parent;
|
||||
|
||||
public Properties knownSpritesheetsProperties = null;
|
||||
|
||||
public static enum ResourceSet {
|
||||
gameData,
|
||||
debugData,
|
||||
allFiles
|
||||
}
|
||||
|
||||
public ResourceSet sourceSetToUse = ResourceSet.allFiles;
|
||||
|
||||
public Project(Workspace w, String name, File source) {
|
||||
public Project(Workspace w, String name, File source, ResourceSet sourceSet) {
|
||||
this.parent = w;
|
||||
this.name = name;
|
||||
this.sourceSetToUse = sourceSet;
|
||||
|
||||
//CREATE PROJECT
|
||||
baseFolder = new File(w.baseFolder, name+File.separator);
|
||||
@@ -180,7 +192,7 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
}
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return name;
|
||||
return (needsSaving() ? "*" : "")+name;
|
||||
}
|
||||
|
||||
|
||||
@@ -210,14 +222,16 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
public void refreshTransients(Workspace w) {
|
||||
this.parent = w;
|
||||
|
||||
if (knownSpritesheetsProperties == null) {
|
||||
try {
|
||||
knownSpritesheetsProperties = new Properties();
|
||||
knownSpritesheetsProperties.load(Project.class.getResourceAsStream("/spritesheets.properties"));
|
||||
} catch (IOException e) {
|
||||
Notification.addWarn("Unable to load default spritesheets properties.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
knownSpritesheetsProperties = new Properties();
|
||||
knownSpritesheetsProperties.load(Project.class.getResourceAsStream("/spritesheets.properties"));
|
||||
} catch (IOException e) {
|
||||
Notification.addWarn("Unable to load default spritesheets properties.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (sourceSetToUse == null) {
|
||||
sourceSetToUse = ResourceSet.allFiles;
|
||||
}
|
||||
|
||||
// long l = new Date().getTime();
|
||||
@@ -252,7 +266,7 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
}
|
||||
}
|
||||
for (ProjectTreeNode node : baseContent.gameMaps.tmxMaps) {
|
||||
((TMXMap)node).parse();
|
||||
((TMXMap)node).link();
|
||||
}
|
||||
for (ProjectTreeNode node : alteredContent.gameData.v.getNonEmptyIterable()) {
|
||||
if (node instanceof GameDataCategory<?>) {
|
||||
@@ -262,7 +276,7 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
}
|
||||
}
|
||||
for (ProjectTreeNode node : alteredContent.gameMaps.tmxMaps) {
|
||||
((TMXMap)node).parse();
|
||||
((TMXMap)node).link();
|
||||
}
|
||||
for (ProjectTreeNode node : createdContent.gameData.v.getNonEmptyIterable()) {
|
||||
if (node instanceof GameDataCategory<?>) {
|
||||
@@ -272,9 +286,6 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
}
|
||||
}
|
||||
for (ProjectTreeNode node : createdContent.gameMaps.tmxMaps) {
|
||||
((TMXMap)node).parse();
|
||||
}
|
||||
for (ProjectTreeNode node : baseContent.gameMaps.tmxMaps) {
|
||||
((TMXMap)node).link();
|
||||
}
|
||||
|
||||
@@ -477,6 +488,21 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getItemCountIncludingAltered() {
|
||||
return createdContent.gameData.items.size() + alteredContent.gameData.items.size() + baseContent.gameData.items.size();
|
||||
}
|
||||
|
||||
public Item getItemIncludingAltered(int index) {
|
||||
if (index < createdContent.gameData.items.size()) {
|
||||
return createdContent.gameData.items.get(index);
|
||||
} else if (index < createdContent.gameData.items.size() + alteredContent.gameData.items.size()){
|
||||
return alteredContent.gameData.items.get(index - createdContent.gameData.items.size());
|
||||
} else if (index < getItemCountIncludingAltered()) {
|
||||
return baseContent.gameData.items.get(index - (createdContent.gameData.items.size() + alteredContent.gameData.items.size()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getItemIndex(Item item) {
|
||||
if (item.getDataType() == GameSource.Type.created) {
|
||||
return createdContent.gameData.items.getIndex(item);
|
||||
@@ -542,6 +568,21 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getNPCCountIncludingAltered() {
|
||||
return createdContent.gameData.npcs.size() + alteredContent.gameData.npcs.size() + baseContent.gameData.npcs.size();
|
||||
}
|
||||
|
||||
public NPC getNPCIncludingAltered(int index) {
|
||||
if (index < createdContent.gameData.npcs.size()) {
|
||||
return createdContent.gameData.npcs.get(index);
|
||||
} else if (index < createdContent.gameData.npcs.size() + alteredContent.gameData.npcs.size()){
|
||||
return alteredContent.gameData.npcs.get(index - createdContent.gameData.npcs.size());
|
||||
} else if (index < getNPCCountIncludingAltered()) {
|
||||
return baseContent.gameData.npcs.get(index - (createdContent.gameData.npcs.size() + alteredContent.gameData.npcs.size()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getNPCIndex(NPC npc) {
|
||||
if (npc.getDataType() == GameSource.Type.created) {
|
||||
return createdContent.gameData.npcs.getIndex(npc);
|
||||
@@ -622,6 +663,26 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
return sheet;
|
||||
}
|
||||
|
||||
public int getSpritesheetCount() {
|
||||
return createdContent.gameSprites.spritesheets.size() + baseContent.gameSprites.spritesheets.size();
|
||||
}
|
||||
|
||||
public Spritesheet getSpritesheet(int index) {
|
||||
if (index < createdContent.gameSprites.spritesheets.size()) {
|
||||
return createdContent.gameSprites.spritesheets.get(index);
|
||||
} else if (index < getSpritesheetCount()){
|
||||
return getSpritesheet(baseContent.gameSprites.spritesheets.get(index - createdContent.gameSprites.spritesheets.size()).id);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getSpritesheetIndex(Spritesheet spritesheet) {
|
||||
if (spritesheet.getDataType() == GameSource.Type.created) {
|
||||
return createdContent.gameSprites.spritesheets.indexOf(spritesheet);
|
||||
} else {
|
||||
return createdContent.gameSprites.spritesheets.size() + baseContent.gameSprites.spritesheets.indexOf(baseContent.gameSprites.getSpritesheet(spritesheet.id));
|
||||
}
|
||||
}
|
||||
|
||||
public TMXMap getMap(String id) {
|
||||
TMXMap map = createdContent.gameMaps.getMap(id);
|
||||
@@ -651,6 +712,20 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
public int getWriterSketchCount() {
|
||||
return createdContent.writerModeDataSet.getChildCount();
|
||||
}
|
||||
|
||||
public WriterModeData getWriterSketch(String id) {
|
||||
return createdContent.writerModeDataSet.getWriterSketch(id);
|
||||
}
|
||||
|
||||
public WriterModeData getWriterSketch(int index) {
|
||||
if (index < createdContent.writerModeDataSet.getChildCount()) {
|
||||
return createdContent.writerModeDataSet.get(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project getProject() {
|
||||
@@ -684,6 +759,15 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
} else {
|
||||
if (type == GameSource.Type.source) {
|
||||
JSONElement clone = (JSONElement) node.clone();
|
||||
if (node instanceof Quest) {
|
||||
for (QuestStage oldStage : ((Quest) node).stages) {
|
||||
QuestStage newStage = ((Quest) clone).getStage(oldStage.progress);
|
||||
for (GameDataElement backlink : oldStage.getBacklinks()) {
|
||||
backlink.elementChanged(oldStage, newStage);
|
||||
}
|
||||
oldStage.getBacklinks().clear();
|
||||
}
|
||||
}
|
||||
for (GameDataElement backlink : node.getBacklinks()) {
|
||||
backlink.elementChanged(node, clone);
|
||||
}
|
||||
@@ -743,7 +827,7 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param node. Before calling this method, make sure that no other node with the same class exist in either created or altered.
|
||||
* @param node. Before calling this method, make sure that no other node with the same class and id exist in either created or altered.
|
||||
*/
|
||||
public void createElement(JSONElement node) {
|
||||
node.writable = true;
|
||||
@@ -765,6 +849,62 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
fireElementAdded(node, getNodeIndex(node));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param node. Before calling this method, make sure that no other node with the same class and id exist in either created or altered.
|
||||
*/
|
||||
public void createElements(List<? extends JSONElement> nodes) {
|
||||
for (JSONElement node : nodes) {
|
||||
//Already added.
|
||||
if (node.getProject() != null) continue;
|
||||
node.writable = true;
|
||||
if (getGameDataElement(node.getClass(), node.id) != null) {
|
||||
GameDataElement existingNode = getGameDataElement(node.getClass(), node.id);
|
||||
for (GameDataElement backlink : existingNode.getBacklinks()) {
|
||||
backlink.elementChanged(existingNode, node);
|
||||
}
|
||||
existingNode.getBacklinks().clear();
|
||||
node.writable = true;
|
||||
alteredContent.gameData.addElement(node);
|
||||
} else {
|
||||
createdContent.gameData.addElement(node);
|
||||
}
|
||||
}
|
||||
for (JSONElement node : nodes) {
|
||||
node.link();
|
||||
node.state = GameDataElement.State.created;
|
||||
fireElementAdded(node, getNodeIndex(node));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param node. Before calling this method, make sure that no other map with the same id exist in either created or altered.
|
||||
*/
|
||||
public void createElement(TMXMap node) {
|
||||
node.writable = true;
|
||||
if (getMap(node.id) != null) {
|
||||
GameDataElement existingNode = getMap(node.id);
|
||||
for (GameDataElement backlink : existingNode.getBacklinks()) {
|
||||
backlink.elementChanged(existingNode, node);
|
||||
}
|
||||
existingNode.getBacklinks().clear();
|
||||
node.writable = true;
|
||||
node.tmxFile = new File(alteredContent.baseFolder, node.tmxFile.getName());
|
||||
node.parent = alteredContent.gameMaps;
|
||||
alteredContent.gameMaps.addMap(node);
|
||||
node.link();
|
||||
node.state = GameDataElement.State.created;
|
||||
} else {
|
||||
node.tmxFile = new File(createdContent.baseFolder, node.tmxFile.getName());
|
||||
node.parent = createdContent.gameMaps;
|
||||
createdContent.gameMaps.addMap(node);
|
||||
node.link();
|
||||
node.state = GameDataElement.State.created;
|
||||
}
|
||||
fireElementAdded(node, getNodeIndex(node));
|
||||
}
|
||||
|
||||
|
||||
public void moveToCreated(JSONElement target) {
|
||||
target.childrenRemoved(new ArrayList<ProjectTreeNode>());
|
||||
@@ -801,6 +941,15 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
fireElementAdded(node, getNodeIndex(node));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void createWriterSketch(WriterModeData node) {
|
||||
node.writable = true;
|
||||
createdContent.writerModeDataSet.add(node);
|
||||
node.link();
|
||||
fireElementAdded(node, getNodeIndex(node));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public GameDataSet getDataSet() {
|
||||
@@ -952,8 +1101,8 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void writeAltered(GameDataCategory<? extends JSONElement> altered, GameDataCategory<? extends JSONElement> source, Class<? extends JSONElement> gdeClass, File targetFolder) {
|
||||
Set<String> alteredFileNames = new HashSet<String>();
|
||||
Map<String, List<Map>> toWrite = new HashMap<String, List<Map>>();
|
||||
Set<String> alteredFileNames = new LinkedHashSet<String>();
|
||||
Map<String, List<Map>> toWrite = new LinkedHashMap<String, List<Map>>();
|
||||
for (JSONElement gde : altered) {
|
||||
alteredFileNames.add(gde.jsonFile.getName());
|
||||
}
|
||||
@@ -989,6 +1138,14 @@ public class Project implements ProjectTreeNode, Serializable {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
for (ProjectTreeNode node : v.getNonEmptyIterable()) {
|
||||
if (node.needsSaving()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -53,5 +53,7 @@ public interface ProjectTreeNode extends TreeNode {
|
||||
public GameSource.Type getDataType();
|
||||
|
||||
public boolean isEmpty();
|
||||
|
||||
public boolean needsSaving();
|
||||
|
||||
}
|
||||
|
||||
@@ -21,50 +21,54 @@ import com.gpl.rpg.atcontentstudio.Notification;
|
||||
import com.gpl.rpg.atcontentstudio.io.SettingsSave;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
|
||||
import com.gpl.rpg.atcontentstudio.ui.WorkerDialog;
|
||||
import com.gpl.rpg.atcontentstudio.ui.ProjectsTree.ProjectsTreeModel;
|
||||
import com.gpl.rpg.atcontentstudio.ui.WorkerDialog;
|
||||
|
||||
public class Workspace implements ProjectTreeNode, Serializable {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 7938633033601384956L;
|
||||
|
||||
public static final String WS_SETTINGS_FILE = ".workspace";
|
||||
|
||||
|
||||
public static Workspace activeWorkspace;
|
||||
|
||||
|
||||
public Preferences preferences = new Preferences();
|
||||
public File baseFolder;
|
||||
public File settingsFile;
|
||||
public transient WorkspaceSettings settings;
|
||||
public transient List<ProjectTreeNode> projects = new ArrayList<ProjectTreeNode>();
|
||||
public Set<String> projectsName = new HashSet<String>();
|
||||
public Map<String, Boolean> projectsOpenByName = new HashMap<String, Boolean>();
|
||||
public Set<File> knownMapSourcesFolders = new HashSet<File>();
|
||||
|
||||
|
||||
public transient ProjectsTreeModel projectsTreeModel = null;
|
||||
|
||||
|
||||
public Workspace(File workspaceRoot) {
|
||||
baseFolder = workspaceRoot;
|
||||
if (!workspaceRoot.exists()) {
|
||||
try {
|
||||
workspaceRoot.mkdir();
|
||||
} catch (SecurityException e) {
|
||||
Notification.addError("Error creating workspace directory: "+e.getMessage());
|
||||
Notification.addError("Error creating workspace directory: "
|
||||
+ e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
settings = new WorkspaceSettings(this);
|
||||
settingsFile = new File(workspaceRoot, WS_SETTINGS_FILE);
|
||||
if (!settingsFile.exists()) {
|
||||
try {
|
||||
settingsFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
Notification.addError("Error creating workspace datafile: "+e.getMessage());
|
||||
Notification.addError("Error creating workspace datafile: "
|
||||
+ e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
Notification.addSuccess("New workspace created: "+workspaceRoot.getAbsolutePath());
|
||||
Notification.addSuccess("New workspace created: "
|
||||
+ workspaceRoot.getAbsolutePath());
|
||||
save();
|
||||
}
|
||||
|
||||
|
||||
public static void setActive(File workspaceRoot) {
|
||||
Workspace w = null;
|
||||
@@ -81,12 +85,13 @@ public class Workspace implements ProjectTreeNode, Serializable {
|
||||
}
|
||||
activeWorkspace = w;
|
||||
}
|
||||
|
||||
|
||||
public static void saveActive() {
|
||||
activeWorkspace.save();
|
||||
}
|
||||
|
||||
|
||||
public void save() {
|
||||
settings.save();
|
||||
SettingsSave.saveInstance(this, settingsFile, "Workspace");
|
||||
}
|
||||
|
||||
@@ -94,82 +99,111 @@ public class Workspace implements ProjectTreeNode, Serializable {
|
||||
public Enumeration<ProjectTreeNode> children() {
|
||||
return Collections.enumeration(projects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAllowsChildren() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeNode getChildAt(int arg0) {
|
||||
return projects.get(arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount() {
|
||||
return projects.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex(TreeNode arg0) {
|
||||
return projects.indexOf(arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeNode getParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeaf() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenAdded(List<ProjectTreeNode> path) {
|
||||
path.add(0, this);
|
||||
if (projectsTreeModel != null) projectsTreeModel.insertNode(new TreePath(path.toArray()));
|
||||
if (projectsTreeModel != null)
|
||||
projectsTreeModel.insertNode(new TreePath(path.toArray()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenChanged(List<ProjectTreeNode> path) {
|
||||
path.add(0, this);
|
||||
if (projectsTreeModel != null) projectsTreeModel.changeNode(new TreePath(path.toArray()));
|
||||
ProjectTreeNode last = path.get(path.size() - 1);
|
||||
if (projectsTreeModel != null) {
|
||||
while (path.size() > 1) {
|
||||
projectsTreeModel.changeNode(new TreePath(path.toArray()));
|
||||
path.remove(path.size()-1);
|
||||
}
|
||||
|
||||
}
|
||||
ATContentStudio.frame.editorChanged(last);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenRemoved(List<ProjectTreeNode> path) {
|
||||
path.add(0, this);
|
||||
if (projectsTreeModel != null) projectsTreeModel.removeNode(new TreePath(path.toArray()));
|
||||
if (projectsTreeModel != null)
|
||||
projectsTreeModel.removeNode(new TreePath(path.toArray()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyCreated() {
|
||||
childrenAdded(new ArrayList<ProjectTreeNode>());
|
||||
for (ProjectTreeNode node : projects) {
|
||||
if (node != null) node.notifyCreated();
|
||||
if (node != null)
|
||||
node.notifyCreated();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return "Workspace: "+baseFolder.getAbsolutePath();
|
||||
return "Workspace: " + baseFolder.getAbsolutePath();
|
||||
}
|
||||
|
||||
|
||||
public static void createProject(final String projectName, final File gameSourceFolder) {
|
||||
WorkerDialog.showTaskMessage("Creating project "+projectName+"...", ATContentStudio.frame, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (activeWorkspace.projectsName.contains(projectName)) {
|
||||
Notification.addError("A project named "+projectName+" already exists in this workspace.");
|
||||
return;
|
||||
}
|
||||
Project p = new Project(activeWorkspace, projectName, gameSourceFolder);
|
||||
activeWorkspace.projects.add(p);
|
||||
activeWorkspace.projectsName.add(projectName);
|
||||
activeWorkspace.projectsOpenByName.put(projectName, p.open);
|
||||
activeWorkspace.knownMapSourcesFolders.add(gameSourceFolder);
|
||||
p.notifyCreated();
|
||||
Notification.addSuccess("Project "+projectName+" successfully created");
|
||||
saveActive();
|
||||
}
|
||||
});
|
||||
public static void createProject(final String projectName,
|
||||
final File gameSourceFolder, final Project.ResourceSet sourceSet) {
|
||||
WorkerDialog.showTaskMessage("Creating project " + projectName + "...",
|
||||
ATContentStudio.frame, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (activeWorkspace.projectsName.contains(projectName)) {
|
||||
Notification.addError("A project named "
|
||||
+ projectName
|
||||
+ " already exists in this workspace.");
|
||||
return;
|
||||
}
|
||||
Project p = new Project(activeWorkspace, projectName,
|
||||
gameSourceFolder, sourceSet);
|
||||
activeWorkspace.projects.add(p);
|
||||
activeWorkspace.projectsName.add(projectName);
|
||||
activeWorkspace.projectsOpenByName.put(projectName,
|
||||
p.open);
|
||||
activeWorkspace.knownMapSourcesFolders
|
||||
.add(gameSourceFolder);
|
||||
p.notifyCreated();
|
||||
Notification.addSuccess("Project " + projectName
|
||||
+ " successfully created");
|
||||
saveActive();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static void closeProject(Project p) {
|
||||
int index = activeWorkspace.projects.indexOf(p);
|
||||
if (index < 0) {
|
||||
Notification.addError("Cannot close unknown project "+p.name);
|
||||
Notification.addError("Cannot close unknown project " + p.name);
|
||||
return;
|
||||
}
|
||||
p.close();
|
||||
@@ -179,28 +213,33 @@ public class Workspace implements ProjectTreeNode, Serializable {
|
||||
cp.notifyCreated();
|
||||
saveActive();
|
||||
}
|
||||
|
||||
|
||||
public static void openProject(final ClosedProject cp) {
|
||||
WorkerDialog.showTaskMessage("Opening project "+cp.name+"...", ATContentStudio.frame, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int index = activeWorkspace.projects.indexOf(cp);
|
||||
if (index < 0) {
|
||||
Notification.addError("Cannot open unknown project "+cp.name);
|
||||
return;
|
||||
}
|
||||
cp.childrenRemoved(new ArrayList<ProjectTreeNode>());
|
||||
Project p = Project.fromFolder(activeWorkspace, new File(activeWorkspace.baseFolder, cp.name));
|
||||
p.open();
|
||||
activeWorkspace.projects.set(index, p);
|
||||
activeWorkspace.projectsOpenByName.put(p.name, true);
|
||||
p.notifyCreated();
|
||||
saveActive();
|
||||
}
|
||||
});
|
||||
WorkerDialog.showTaskMessage("Opening project " + cp.name + "...",
|
||||
ATContentStudio.frame, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int index = activeWorkspace.projects.indexOf(cp);
|
||||
if (index < 0) {
|
||||
Notification
|
||||
.addError("Cannot open unknown project "
|
||||
+ cp.name);
|
||||
return;
|
||||
}
|
||||
cp.childrenRemoved(new ArrayList<ProjectTreeNode>());
|
||||
Project p = Project.fromFolder(activeWorkspace,
|
||||
new File(activeWorkspace.baseFolder, cp.name));
|
||||
p.open();
|
||||
activeWorkspace.projects.set(index, p);
|
||||
activeWorkspace.projectsOpenByName.put(p.name, true);
|
||||
p.notifyCreated();
|
||||
saveActive();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void refreshTransients() {
|
||||
this.settings = new WorkspaceSettings(this);
|
||||
this.projects = new ArrayList<ProjectTreeNode>();
|
||||
Set<String> projectsFailed = new HashSet<String>();
|
||||
for (String projectName : projectsName) {
|
||||
@@ -211,11 +250,16 @@ public class Workspace implements ProjectTreeNode, Serializable {
|
||||
if (p != null) {
|
||||
projects.add(p);
|
||||
} else {
|
||||
Notification.addError("Failed to open project "+projectName+". Removing it from workspace (not from filesystem though).");
|
||||
Notification
|
||||
.addError("Failed to open project "
|
||||
+ projectName
|
||||
+ ". Removing it from workspace (not from filesystem though).");
|
||||
projectsFailed.add(projectName);
|
||||
}
|
||||
} else {
|
||||
Notification.addError("Unable to find project "+projectName+"'s root folder. Removing it from workspace");
|
||||
Notification.addError("Unable to find project "
|
||||
+ projectName
|
||||
+ "'s root folder. Removing it from workspace");
|
||||
projectsFailed.add(projectName);
|
||||
}
|
||||
} else {
|
||||
@@ -228,21 +272,31 @@ public class Workspace implements ProjectTreeNode, Serializable {
|
||||
}
|
||||
notifyCreated();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getIcon() {return null;}
|
||||
@Override
|
||||
public Image getClosedIcon() {return null;}
|
||||
@Override
|
||||
public Image getLeafIcon() {return null;}
|
||||
@Override
|
||||
public Image getOpenIcon() {return null;}
|
||||
|
||||
@Override
|
||||
public Image getIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getClosedIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getLeafIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getOpenIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void deleteProject(ClosedProject cp) {
|
||||
cp.childrenRemoved(new ArrayList<ProjectTreeNode>());
|
||||
@@ -250,37 +304,41 @@ public class Workspace implements ProjectTreeNode, Serializable {
|
||||
activeWorkspace.projectsOpenByName.remove(cp.name);
|
||||
activeWorkspace.projectsName.remove(cp.name);
|
||||
if (delete(new File(activeWorkspace.baseFolder, cp.name))) {
|
||||
Notification.addSuccess("Closed project "+cp.name+" successfully deleted.");
|
||||
Notification.addSuccess("Closed project " + cp.name
|
||||
+ " successfully deleted.");
|
||||
} else {
|
||||
Notification.addError("Error while deleting closed project "+cp.name+". Files may remain in the workspace.");
|
||||
Notification.addError("Error while deleting closed project "
|
||||
+ cp.name + ". Files may remain in the workspace.");
|
||||
}
|
||||
cp = null;
|
||||
saveActive();
|
||||
}
|
||||
|
||||
|
||||
public static void deleteProject(Project p) {
|
||||
p.childrenRemoved(new ArrayList<ProjectTreeNode>());
|
||||
activeWorkspace.projects.remove(p);
|
||||
activeWorkspace.projectsOpenByName.remove(p.name);
|
||||
activeWorkspace.projectsName.remove(p.name);
|
||||
if (delete(p.baseFolder)) {
|
||||
Notification.addSuccess("Project "+p.name+" successfully deleted.");
|
||||
Notification.addSuccess("Project " + p.name
|
||||
+ " successfully deleted.");
|
||||
} else {
|
||||
Notification.addError("Error while deleting project "+p.name+". Files may remain in the workspace.");
|
||||
Notification.addError("Error while deleting project " + p.name
|
||||
+ ". Files may remain in the workspace.");
|
||||
}
|
||||
p = null;
|
||||
saveActive();
|
||||
}
|
||||
|
||||
|
||||
private static boolean delete(File f) {
|
||||
boolean b = true;
|
||||
if (f.isDirectory()) {
|
||||
for (File c : f.listFiles())
|
||||
b &= delete(c);
|
||||
}
|
||||
return b&= f.delete();
|
||||
return b &= f.delete();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public GameDataSet getDataSet() {
|
||||
return null;
|
||||
@@ -290,11 +348,19 @@ public class Workspace implements ProjectTreeNode, Serializable {
|
||||
public Type getDataType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return projects.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
for (ProjectTreeNode node : projects) {
|
||||
if (node.needsSaving()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
218
src/com/gpl/rpg/atcontentstudio/model/WorkspaceSettings.java
Normal file
@@ -0,0 +1,218 @@
|
||||
package com.gpl.rpg.atcontentstudio.model;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.Notification;
|
||||
import com.gpl.rpg.atcontentstudio.io.JsonPrettyWriter;
|
||||
|
||||
public class WorkspaceSettings {
|
||||
|
||||
public static final String VERSION_KEY = "ATCS_Version";
|
||||
public static final String FILENAME = "workspace_settings.json";
|
||||
|
||||
public static final int SETTINGS_VERSION = 1;
|
||||
|
||||
public Workspace parent;
|
||||
public File file;
|
||||
|
||||
public static Boolean DEFAULT_USE_SYS_MAP_EDITOR = true;
|
||||
public Setting<Boolean> useSystemDefaultMapEditor = new PrimitiveSetting<Boolean>("useSystemDefaultMapEditor", DEFAULT_USE_SYS_MAP_EDITOR);
|
||||
public static String DEFAULT_MAP_EDITOR_COMMAND = "tiled";
|
||||
public Setting<String> mapEditorCommand = new PrimitiveSetting<String>("mapEditorCommand", DEFAULT_MAP_EDITOR_COMMAND);
|
||||
|
||||
public static Boolean DEFAULT_USE_SYS_IMG_VIEWER = true;
|
||||
public Setting<Boolean> useSystemDefaultImageViewer = new PrimitiveSetting<Boolean>("useSystemDefaultImageViewer", DEFAULT_USE_SYS_IMG_VIEWER);
|
||||
public static Boolean DEFAULT_USE_SYS_IMG_EDITOR = false;
|
||||
public Setting<Boolean> useSystemDefaultImageEditor = new PrimitiveSetting<Boolean>("useSystemDefaultImageEditor", DEFAULT_USE_SYS_IMG_EDITOR);
|
||||
public static String DEFAULT_IMG_EDITOR_COMMAND = "gimp";
|
||||
public Setting<String> imageEditorCommand = new PrimitiveSetting<String>("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 Setting<String> translatorLanguage = new NullDefaultPrimitiveSetting<String>("translatorLanguage");
|
||||
public static Boolean DEFAULT_ALLOW_INTERNET = true;
|
||||
public Setting<Boolean> useInternet = new PrimitiveSetting<Boolean>("useInternet", DEFAULT_ALLOW_INTERNET);
|
||||
public static Boolean DEFAULT_CHECK_UPDATE = true;
|
||||
public Setting<Boolean> checkUpdates = new PrimitiveSetting<Boolean>("checkUpdates", DEFAULT_CHECK_UPDATE);
|
||||
|
||||
|
||||
public List<Setting<? extends Object>> settings = new ArrayList<Setting<? extends Object>>();
|
||||
|
||||
public WorkspaceSettings(Workspace parent) {
|
||||
this.parent = parent;
|
||||
settings.add(useSystemDefaultMapEditor);
|
||||
settings.add(mapEditorCommand);
|
||||
settings.add(useSystemDefaultImageViewer);
|
||||
settings.add(useSystemDefaultImageEditor);
|
||||
settings.add(imageEditorCommand);
|
||||
settings.add(translatorLanguage);
|
||||
settings.add(useInternet);
|
||||
settings.add(checkUpdates);
|
||||
file = new File(parent.baseFolder, FILENAME);
|
||||
if (file.exists()) {
|
||||
load(file);
|
||||
}
|
||||
}
|
||||
|
||||
public void load(File f) {
|
||||
JSONParser parser = new JSONParser();
|
||||
FileReader reader = null;
|
||||
try {
|
||||
reader = new FileReader(f);
|
||||
@SuppressWarnings("rawtypes")
|
||||
Map jsonSettings = (Map) parser.parse(reader);
|
||||
Integer version = ((Number) jsonSettings.get(VERSION_KEY)).intValue();
|
||||
if (version != null) {
|
||||
if (version >= 1) {
|
||||
loadv1(jsonSettings);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Notification.addError("Error while parsing workspace settings: "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (reader != null)
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void loadv1(Map jsonSettings) {
|
||||
for (Setting s : settings) {
|
||||
s.readFromJson(jsonSettings);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void save() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Map json = new LinkedHashMap();
|
||||
for (Setting<? extends Object> s : settings) {
|
||||
s.saveToJson(json);
|
||||
}
|
||||
|
||||
if (json.isEmpty()) {
|
||||
//Everything is default.
|
||||
file.delete();
|
||||
return;
|
||||
}
|
||||
|
||||
json.put(VERSION_KEY, SETTINGS_VERSION);
|
||||
StringWriter writer = new JsonPrettyWriter();
|
||||
try {
|
||||
JSONObject.writeJSONString(json, writer);
|
||||
} catch (IOException e) {
|
||||
//Impossible with a StringWriter
|
||||
}
|
||||
String toWrite = writer.toString();
|
||||
try {
|
||||
FileWriter w = new FileWriter(file);
|
||||
w.write(toWrite);
|
||||
w.close();
|
||||
Notification.addSuccess("Workspace settings saved.");
|
||||
} catch (IOException e) {
|
||||
Notification.addError("Error while saving workspace settings : "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void resetDefault() {
|
||||
for (Setting<? extends Object> s : settings) {
|
||||
s.resetDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Setting<X extends Object> {
|
||||
|
||||
public String id;
|
||||
public X value, defaultValue;
|
||||
|
||||
public void setCurrentValue(X value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public X getCurrentValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public X getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void resetDefault() {
|
||||
value = defaultValue;
|
||||
}
|
||||
|
||||
public abstract void readFromJson(Map json);
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void saveToJson(Map json) {
|
||||
if (!defaultValue.equals(value)) json.put(id, value);
|
||||
}
|
||||
}
|
||||
|
||||
public class PrimitiveSetting<X extends Object> extends Setting<X> {
|
||||
|
||||
|
||||
public PrimitiveSetting(String id, X defaultValue) {
|
||||
this.id = id;
|
||||
this.value = this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void readFromJson(Map json) {
|
||||
if (json.get(id) != null) value = (X)json.get(id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class NullDefaultPrimitiveSetting<X extends Object> extends PrimitiveSetting<X> {
|
||||
|
||||
public NullDefaultPrimitiveSetting(String id) {
|
||||
super(id, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveToJson(Map json) {
|
||||
if (value != null) json.put(id, value);
|
||||
}
|
||||
}
|
||||
|
||||
public class ListSetting<X extends Object> extends Setting<List<X>> {
|
||||
|
||||
public ListSetting(String id, List<X> defaultValue) {
|
||||
this.id = id;
|
||||
this.value = this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromJson(Map json) {
|
||||
value = new ArrayList<X>();
|
||||
if (json.get(id) != null) {
|
||||
for (Object o : ((List)json.get(id))) {
|
||||
value.add((X)o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -20,6 +20,8 @@ import com.gpl.rpg.atcontentstudio.model.GameSource;
|
||||
public class ActorCondition extends JSONElement {
|
||||
|
||||
private static final long serialVersionUID = -3969824899972048507L;
|
||||
|
||||
public static final Integer CLEAR_AC_MAGNITUDE = -99;
|
||||
|
||||
// Available from init state
|
||||
//public String id; inherited.
|
||||
@@ -86,7 +88,7 @@ public class ActorCondition extends JSONElement {
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return (this.state == State.modified ? "*" : "")+display_name+" ("+id+")";
|
||||
return (needsSaving() ? "*" : "")+display_name+" ("+id+")";
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@@ -147,7 +149,7 @@ public class ActorCondition extends JSONElement {
|
||||
public void parse(Map aCondJson) {
|
||||
|
||||
if (aCondJson.get("category") != null) this.category = ACCategory.valueOf((String) aCondJson.get("category"));
|
||||
this.positive = JSONElement.getInteger((Number) aCondJson.get("positive"));
|
||||
this.positive = JSONElement.getInteger((Number) aCondJson.get("isPositive"));
|
||||
Map abilityEffect = (Map) aCondJson.get("abilityEffect");
|
||||
if (abilityEffect != null) {
|
||||
this.constant_ability_effect = new AbilityEffect();
|
||||
@@ -264,18 +266,18 @@ public class ActorCondition extends JSONElement {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Map toJson() {
|
||||
Map jsonAC = new HashMap();
|
||||
Map jsonAC = new LinkedHashMap();
|
||||
jsonAC.put("id", this.id);
|
||||
if (this.icon_id != null) jsonAC.put("iconID", this.icon_id);
|
||||
if (this.display_name != null) jsonAC.put("name", this.display_name);
|
||||
if (this.category != null) jsonAC.put("category", this.category.toString());
|
||||
if (this.positive != null && this.positive == 1) jsonAC.put("positive", this.positive);
|
||||
if (this.stacking != null && this.stacking == 1) jsonAC.put("stacking", this.stacking);
|
||||
if (this.positive != null && this.positive == 1) jsonAC.put("isPositive", this.positive);
|
||||
if (this.stacking != null && this.stacking == 1) jsonAC.put("isStacking", this.stacking);
|
||||
if (this.round_effect != null) {
|
||||
Map jsonRound = new HashMap();
|
||||
Map jsonRound = new LinkedHashMap();
|
||||
if (this.round_effect.visual_effect != null) jsonRound.put("visualEffectID", this.round_effect.visual_effect);
|
||||
if (this.round_effect.hp_boost_min != null || this.round_effect.hp_boost_max != null) {
|
||||
Map jsonHP = new HashMap();
|
||||
Map jsonHP = new LinkedHashMap();
|
||||
if (this.round_effect.hp_boost_min != null) jsonHP.put("min", this.round_effect.hp_boost_min);
|
||||
else jsonHP.put("min", 0);
|
||||
if (this.round_effect.hp_boost_max != null) jsonHP.put("max", this.round_effect.hp_boost_max);
|
||||
@@ -283,7 +285,7 @@ public class ActorCondition extends JSONElement {
|
||||
jsonRound.put("increaseCurrentHP", jsonHP);
|
||||
}
|
||||
if (this.round_effect.ap_boost_min != null || this.round_effect.ap_boost_max != null) {
|
||||
Map jsonAP = new HashMap();
|
||||
Map jsonAP = new LinkedHashMap();
|
||||
if (this.round_effect.ap_boost_min != null) jsonAP.put("min", this.round_effect.ap_boost_min);
|
||||
else jsonAP.put("min", 0);
|
||||
if (this.round_effect.ap_boost_max != null) jsonAP.put("max", this.round_effect.ap_boost_max);
|
||||
@@ -293,10 +295,10 @@ public class ActorCondition extends JSONElement {
|
||||
jsonAC.put("roundEffect", jsonRound);
|
||||
}
|
||||
if (this.full_round_effect != null) {
|
||||
Map jsonFullRound = new HashMap();
|
||||
Map jsonFullRound = new LinkedHashMap();
|
||||
if (this.full_round_effect.visual_effect != null) jsonFullRound.put("visualEffectID", this.full_round_effect.visual_effect);
|
||||
if (this.full_round_effect.hp_boost_min != null || this.full_round_effect.hp_boost_max != null) {
|
||||
Map jsonHP = new HashMap();
|
||||
Map jsonHP = new LinkedHashMap();
|
||||
if (this.full_round_effect.hp_boost_min != null) jsonHP.put("min", this.full_round_effect.hp_boost_min);
|
||||
else jsonHP.put("min", 0);
|
||||
if (this.full_round_effect.hp_boost_max != null) jsonHP.put("max", this.full_round_effect.hp_boost_max);
|
||||
@@ -304,7 +306,7 @@ public class ActorCondition extends JSONElement {
|
||||
jsonFullRound.put("increaseCurrentHP", jsonHP);
|
||||
}
|
||||
if (this.full_round_effect.ap_boost_min != null || this.full_round_effect.ap_boost_max != null) {
|
||||
Map jsonAP = new HashMap();
|
||||
Map jsonAP = new LinkedHashMap();
|
||||
if (this.full_round_effect.ap_boost_min != null) jsonAP.put("min", this.full_round_effect.ap_boost_min);
|
||||
else jsonAP.put("min", 0);
|
||||
if (this.full_round_effect.ap_boost_max != null) jsonAP.put("max", this.full_round_effect.ap_boost_max);
|
||||
@@ -314,10 +316,10 @@ public class ActorCondition extends JSONElement {
|
||||
jsonAC.put("fullRoundEffect", jsonFullRound);
|
||||
}
|
||||
if (this.constant_ability_effect != null) {
|
||||
Map jsonAbility = new HashMap();
|
||||
Map jsonAbility = new LinkedHashMap();
|
||||
if (this.constant_ability_effect.increase_attack_chance != null) jsonAbility.put("increaseAttackChance", this.constant_ability_effect.increase_attack_chance);
|
||||
if (this.constant_ability_effect.increase_damage_min != null || this.constant_ability_effect.increase_damage_max != null) {
|
||||
Map jsonAD = new HashMap();
|
||||
Map jsonAD = new LinkedHashMap();
|
||||
if (this.constant_ability_effect.increase_damage_min != null) jsonAD.put("min", this.constant_ability_effect.increase_damage_min);
|
||||
else jsonAD.put("min", 0);
|
||||
if (this.constant_ability_effect.increase_damage_max != null) jsonAD.put("max", this.constant_ability_effect.increase_damage_max);
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -54,6 +54,7 @@ public class Dialogue extends JSONElement {
|
||||
|
||||
public enum RewardType {
|
||||
questProgress,
|
||||
removeQuestProgress,
|
||||
dropList,
|
||||
skillIncrease,
|
||||
actorCondition,
|
||||
@@ -63,8 +64,9 @@ public class Dialogue extends JSONElement {
|
||||
spawnAll,
|
||||
removeSpawnArea,
|
||||
deactivateSpawnArea,
|
||||
activateMapChangeArea,
|
||||
deactivateMapChangeArea
|
||||
activateMapObjectGroup,
|
||||
deactivateMapObjectGroup,
|
||||
changeMapFilter
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +92,7 @@ public class Dialogue extends JSONElement {
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return (this.state == State.modified ? "*" : "")+id;
|
||||
return (needsSaving() ? "*" : "")+id;
|
||||
}
|
||||
|
||||
public static String getStaticDesc() {
|
||||
@@ -223,10 +225,7 @@ public class Dialogue extends JSONElement {
|
||||
if (replies != null) {
|
||||
for (Reply reply : replies) {
|
||||
if (reply.next_phrase_id != null) {
|
||||
if (!reply.next_phrase_id.equals(Reply.EXIT_PHRASE_ID)
|
||||
&& !reply.next_phrase_id.equals(Reply.FIGHT_PHRASE_ID)
|
||||
&& !reply.next_phrase_id.equals(Reply.SHOP_PHRASE_ID)
|
||||
&& !reply.next_phrase_id.equals(Reply.REMOVE_PHRASE_ID)) {
|
||||
if (!Reply.KEY_PHRASE_ID.contains(reply.next_phrase_id)) {
|
||||
reply.next_phrase = proj.getDialogue(reply.next_phrase_id);
|
||||
}
|
||||
}
|
||||
@@ -242,12 +241,13 @@ public class Dialogue extends JSONElement {
|
||||
for (Reward reward : rewards) {
|
||||
if (reward.reward_obj_id != null) {
|
||||
switch (reward.type) {
|
||||
case activateMapChangeArea:
|
||||
case deactivateMapChangeArea:
|
||||
case activateMapObjectGroup:
|
||||
case deactivateMapObjectGroup:
|
||||
case spawnAll:
|
||||
case removeSpawnArea:
|
||||
case deactivateSpawnArea:
|
||||
reward.map = proj.getMap(reward.map_name);
|
||||
case changeMapFilter:
|
||||
reward.map = reward.map_name != null ? proj.getMap(reward.map_name) : null;
|
||||
break;
|
||||
case actorCondition:
|
||||
reward.reward_obj = proj.getActorCondition(reward.reward_obj_id);
|
||||
@@ -265,7 +265,14 @@ public class Dialogue extends JSONElement {
|
||||
reward.reward_obj = proj.getItem(reward.reward_obj_id);
|
||||
break;
|
||||
case questProgress:
|
||||
case removeQuestProgress:
|
||||
reward.reward_obj = proj.getQuest(reward.reward_obj_id);
|
||||
if (reward.reward_obj != null && reward.reward_value != null) {
|
||||
QuestStage stage = ((Quest)reward.reward_obj).getStage(reward.reward_value);
|
||||
if (stage != null) {
|
||||
stage.addBacklink(this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case skillIncrease:
|
||||
//Nothing to do (yet ?).
|
||||
@@ -315,6 +322,11 @@ public class Dialogue extends JSONElement {
|
||||
if (rclone.reward_obj != null) {
|
||||
rclone.reward_obj.addBacklink(clone);
|
||||
}
|
||||
rclone.map = r.map;
|
||||
rclone.map_name = r.map_name;
|
||||
if (rclone.map != null) {
|
||||
rclone.map.addBacklink(clone);
|
||||
}
|
||||
clone.rewards.add(rclone);
|
||||
}
|
||||
}
|
||||
@@ -344,21 +356,20 @@ public class Dialogue extends JSONElement {
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
if (switch_to_npc == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
switch_to_npc = (NPC) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
} else {
|
||||
if (replies != null) {
|
||||
for (Reply r : replies) {
|
||||
if (r.next_phrase == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
r.next_phrase = (Dialogue) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
}
|
||||
if (r.requirements != null) {
|
||||
for (Requirement req : r.requirements) {
|
||||
if (req.required_obj == oldOne) {
|
||||
req.required_obj = newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
}
|
||||
req.elementChanged(oldOne, newOne);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,9 +377,16 @@ public class Dialogue extends JSONElement {
|
||||
if (rewards != null) {
|
||||
for (Reward r : rewards) {
|
||||
if (r.reward_obj == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
r.reward_obj = newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
}
|
||||
if (oldOne instanceof QuestStage) {
|
||||
if (r.reward_obj != null && r.reward_obj.equals(oldOne.parent) && r.reward_value != null && r.reward_value.equals(((QuestStage) oldOne).progress)) {
|
||||
oldOne.removeBacklink((GameDataElement) this);
|
||||
if (newOne != null) newOne.addBacklink((GameDataElement) this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -377,7 +395,7 @@ public class Dialogue extends JSONElement {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Map toJson() {
|
||||
Map dialogueJson = new HashMap();
|
||||
Map dialogueJson = new LinkedHashMap();
|
||||
dialogueJson.put("id", this.id);
|
||||
if (this.message != null) dialogueJson.put("message", this.message);
|
||||
if (this.switch_to_npc != null) {
|
||||
@@ -389,7 +407,7 @@ public class Dialogue extends JSONElement {
|
||||
List repliesJson = new ArrayList();
|
||||
dialogueJson.put("replies", repliesJson);
|
||||
for (Reply reply : this.replies){
|
||||
Map replyJson = new HashMap();
|
||||
Map replyJson = new LinkedHashMap();
|
||||
repliesJson.add(replyJson);
|
||||
if (reply.text != null) replyJson.put("text", reply.text);
|
||||
if (reply.next_phrase != null) {
|
||||
@@ -401,7 +419,7 @@ public class Dialogue extends JSONElement {
|
||||
List requirementsJson = new ArrayList();
|
||||
replyJson.put("requires", requirementsJson);
|
||||
for (Requirement requirement : reply.requirements) {
|
||||
Map requirementJson = new HashMap();
|
||||
Map requirementJson = new LinkedHashMap();
|
||||
requirementsJson.add(requirementJson);
|
||||
if (requirement.type != null) requirementJson.put("requireType", requirement.type.toString());
|
||||
if (requirement.required_obj != null) {
|
||||
@@ -421,7 +439,7 @@ public class Dialogue extends JSONElement {
|
||||
List rewardsJson = new ArrayList();
|
||||
dialogueJson.put("rewards", rewardsJson);
|
||||
for (Reward reward : this.rewards) {
|
||||
Map rewardJson = new HashMap();
|
||||
Map rewardJson = new LinkedHashMap();
|
||||
rewardsJson.add(rewardJson);
|
||||
if (reward.type != null) rewardJson.put("rewardType", reward.type.toString());
|
||||
if (reward.reward_obj != null) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -46,7 +46,7 @@ public class Droplist extends JSONElement {
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return (this.state == State.modified ? "*" : "")+id;
|
||||
return (needsSaving() ? "*" : "")+id;
|
||||
}
|
||||
|
||||
public static String getStaticDesc() {
|
||||
@@ -193,6 +193,7 @@ public class Droplist extends JSONElement {
|
||||
if (dropped_items != null) {
|
||||
for (DroppedItem di : dropped_items) {
|
||||
if (di.item == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
di.item = (Item) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
}
|
||||
@@ -203,13 +204,13 @@ public class Droplist extends JSONElement {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Map toJson() {
|
||||
Map droplistJson = new HashMap();
|
||||
Map droplistJson = new LinkedHashMap();
|
||||
droplistJson.put("id", this.id);
|
||||
if (this.dropped_items != null) {
|
||||
List droppedItemsJson = new ArrayList();
|
||||
droplistJson.put("items", droppedItemsJson);
|
||||
for (DroppedItem droppedItem : this.dropped_items) {
|
||||
Map droppedItemJson = new HashMap();
|
||||
Map droppedItemJson = new LinkedHashMap();
|
||||
droppedItemsJson.add(droppedItemJson);
|
||||
if (droppedItem.item != null) {
|
||||
droppedItemJson.put("itemID", droppedItem.item.id);
|
||||
@@ -218,7 +219,7 @@ public class Droplist extends JSONElement {
|
||||
}
|
||||
if (droppedItem.chance != null) droppedItemJson.put("chance", JSONElement.printJsonChance(droppedItem.chance));
|
||||
if (droppedItem.quantity_min != null || droppedItem.quantity_max != null) {
|
||||
Map quantityJson = new HashMap();
|
||||
Map quantityJson = new LinkedHashMap();
|
||||
droppedItemJson.put("quantity", quantityJson);
|
||||
if (droppedItem.quantity_min != null) quantityJson.put("min", droppedItem.quantity_min);
|
||||
else quantityJson.put("min", 0);
|
||||
|
||||
@@ -9,7 +9,7 @@ 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.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -102,7 +102,7 @@ public class GameDataCategory<E extends JSONElement> extends ArrayList<E> implem
|
||||
}
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return this.name;
|
||||
return (needsSaving() ? "*" : "")+this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,7 +154,7 @@ public class GameDataCategory<E extends JSONElement> extends ArrayList<E> implem
|
||||
dataToSave.add(element.toJson());
|
||||
}
|
||||
}
|
||||
if (dataToSave.isEmpty()) {
|
||||
if (dataToSave.isEmpty() && jsonFile.exists()) {
|
||||
if (jsonFile.delete()) {
|
||||
Notification.addSuccess("File "+jsonFile.getAbsolutePath()+" deleted.");
|
||||
} else {
|
||||
@@ -190,7 +190,7 @@ public class GameDataCategory<E extends JSONElement> extends ArrayList<E> implem
|
||||
List<SaveEvent> events = new ArrayList<SaveEvent>();
|
||||
GameDataCategory<? extends JSONElement> impactedCategory = null;
|
||||
String impactedFileName = fileName;
|
||||
Map<String, Integer> containedIds = new HashMap<String, Integer>();
|
||||
Map<String, Integer> containedIds = new LinkedHashMap<String, Integer>();
|
||||
for (JSONElement node : this) {
|
||||
if (node.getDataType() == GameSource.Type.created && getProject().baseContent.gameData.getGameDataElement(node.getClass(), node.id) != null) {
|
||||
if (getProject().alteredContent.gameData.getGameDataElement(node.getClass(), node.id) != null) {
|
||||
@@ -208,7 +208,7 @@ public class GameDataCategory<E extends JSONElement> extends ArrayList<E> implem
|
||||
impactedCategory = getProject().createdContent.gameData.getCategory(node.getClass());
|
||||
impactedFileName = node.getProjectFilename();
|
||||
}
|
||||
} else if (node.state == GameDataElement.State.modified) {
|
||||
} else if (node.needsSaving()) {
|
||||
events.add(new SaveEvent(SaveEvent.Type.alsoSave, node));
|
||||
}
|
||||
if (containedIds.containsKey(node.id)) {
|
||||
@@ -242,5 +242,12 @@ public class GameDataCategory<E extends JSONElement> extends ArrayList<E> implem
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
for (E node : this) {
|
||||
if (node.needsSaving()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.gpl.rpg.atcontentstudio.Notification;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
|
||||
import com.gpl.rpg.atcontentstudio.model.Project;
|
||||
import com.gpl.rpg.atcontentstudio.model.Project.ResourceSet;
|
||||
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
|
||||
import com.gpl.rpg.atcontentstudio.model.SavedSlotCollection;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
@@ -25,6 +26,17 @@ public class GameDataSet implements ProjectTreeNode, Serializable {
|
||||
public static final String DEFAULT_REL_PATH_IN_SOURCE = "res"+File.separator+"raw"+File.separator;
|
||||
public static final String DEFAULT_REL_PATH_IN_PROJECT = "json"+File.separator;
|
||||
|
||||
public static final String GAME_AC_ARRAY_NAME = "loadresource_actorconditions";
|
||||
public static final String GAME_DIALOGUES_ARRAY_NAME = "loadresource_conversationlists";
|
||||
public static final String GAME_DROPLISTS_ARRAY_NAME = "loadresource_droplists";
|
||||
public static final String GAME_ITEMS_ARRAY_NAME = "loadresource_items";
|
||||
public static final String GAME_ITEMCAT_ARRAY_NAME = "loadresource_itemcategories";
|
||||
public static final String GAME_NPC_ARRAY_NAME = "loadresource_monsters";
|
||||
public static final String GAME_QUESTS_ARRAY_NAME = "loadresource_quests";
|
||||
public static final String DEBUG_SUFFIX = "_debug";
|
||||
public static final String RESOURCE_PREFIX = "@raw/";
|
||||
public static final String FILENAME_SUFFIX = ".json";
|
||||
|
||||
public File baseFolder;
|
||||
|
||||
public GameDataCategory<ActorCondition> actorConditions;
|
||||
@@ -67,7 +79,87 @@ public class GameDataSet implements ProjectTreeNode, Serializable {
|
||||
v.add(quests);
|
||||
|
||||
//Start parsing to populate categories' content.
|
||||
if (parent.type != GameSource.Type.referenced) {
|
||||
if (parent.type == GameSource.Type.source && (parent.parent.sourceSetToUse == ResourceSet.debugData || parent.parent.sourceSetToUse == ResourceSet.gameData)) {
|
||||
String suffix = (parent.parent.sourceSetToUse == ResourceSet.debugData) ? DEBUG_SUFFIX : "";
|
||||
|
||||
if (parent.referencedSourceFiles.get(GAME_AC_ARRAY_NAME+suffix) != null) {
|
||||
for (String resource : parent.referencedSourceFiles.get(GAME_AC_ARRAY_NAME+suffix)) {
|
||||
File f = new File(baseFolder, resource.replaceAll(RESOURCE_PREFIX, "")+FILENAME_SUFFIX);
|
||||
if (f.exists()) {
|
||||
ActorCondition.fromJson(f, actorConditions);
|
||||
} else {
|
||||
Notification.addWarn("Unable to locate resource "+resource+" in the game source for project "+getProject().name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parent.referencedSourceFiles.get(GAME_DIALOGUES_ARRAY_NAME+suffix) != null) {
|
||||
for (String resource : parent.referencedSourceFiles.get(GAME_DIALOGUES_ARRAY_NAME+suffix)) {
|
||||
File f = new File(baseFolder, resource.replaceAll(RESOURCE_PREFIX, "")+FILENAME_SUFFIX);
|
||||
if (f.exists()) {
|
||||
Dialogue.fromJson(f, dialogues);
|
||||
} else {
|
||||
Notification.addWarn("Unable to locate resource "+resource+" in the game source for project "+getProject().name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parent.referencedSourceFiles.get(GAME_DROPLISTS_ARRAY_NAME+suffix) != null) {
|
||||
for (String resource : parent.referencedSourceFiles.get(GAME_DROPLISTS_ARRAY_NAME+suffix)) {
|
||||
File f = new File(baseFolder, resource.replaceAll(RESOURCE_PREFIX, "")+FILENAME_SUFFIX);
|
||||
if (f.exists()) {
|
||||
Droplist.fromJson(f, droplists);
|
||||
} else {
|
||||
Notification.addWarn("Unable to locate resource "+resource+" in the game source for project "+getProject().name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parent.referencedSourceFiles.get(GAME_ITEMS_ARRAY_NAME+suffix) != null) {
|
||||
for (String resource : parent.referencedSourceFiles.get(GAME_ITEMS_ARRAY_NAME+suffix)) {
|
||||
File f = new File(baseFolder, resource.replaceAll(RESOURCE_PREFIX, "")+FILENAME_SUFFIX);
|
||||
if (f.exists()) {
|
||||
Item.fromJson(f, items);
|
||||
} else {
|
||||
Notification.addWarn("Unable to locate resource "+resource+" in the game source for project "+getProject().name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parent.referencedSourceFiles.get(GAME_ITEMCAT_ARRAY_NAME+suffix) != null) {
|
||||
for (String resource : parent.referencedSourceFiles.get(GAME_ITEMCAT_ARRAY_NAME+suffix)) {
|
||||
File f = new File(baseFolder, resource.replaceAll(RESOURCE_PREFIX, "")+FILENAME_SUFFIX);
|
||||
if (f.exists()) {
|
||||
ItemCategory.fromJson(f, itemCategories);
|
||||
} else {
|
||||
Notification.addWarn("Unable to locate resource "+resource+" in the game source for project "+getProject().name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parent.referencedSourceFiles.get(GAME_NPC_ARRAY_NAME+suffix) != null) {
|
||||
for (String resource : parent.referencedSourceFiles.get(GAME_NPC_ARRAY_NAME+suffix)) {
|
||||
File f = new File(baseFolder, resource.replaceAll(RESOURCE_PREFIX, "")+FILENAME_SUFFIX);
|
||||
if (f.exists()) {
|
||||
NPC.fromJson(f, npcs);
|
||||
} else {
|
||||
Notification.addWarn("Unable to locate resource "+resource+" in the game source for project "+getProject().name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parent.referencedSourceFiles.get(GAME_QUESTS_ARRAY_NAME+suffix) != null) {
|
||||
for (String resource : parent.referencedSourceFiles.get(GAME_QUESTS_ARRAY_NAME+suffix)) {
|
||||
File f = new File(baseFolder, resource.replaceAll(RESOURCE_PREFIX, "")+FILENAME_SUFFIX);
|
||||
if (f.exists()) {
|
||||
Quest.fromJson(f, quests);
|
||||
} else {
|
||||
Notification.addWarn("Unable to locate resource "+resource+" in the game source for project "+getProject().name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (parent.type != GameSource.Type.referenced) {
|
||||
for (File f : baseFolder.listFiles()) {
|
||||
if (f.getName().startsWith("actorconditions_")) {
|
||||
ActorCondition.fromJson(f, actorConditions);
|
||||
@@ -144,7 +236,7 @@ public class GameDataSet implements ProjectTreeNode, Serializable {
|
||||
}
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return "JSON data";
|
||||
return (needsSaving() ? "*" : "")+"JSON data";
|
||||
}
|
||||
|
||||
|
||||
@@ -371,4 +463,11 @@ public class GameDataSet implements ProjectTreeNode, Serializable {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
for (ProjectTreeNode node : v.getNonEmptyIterable()) {
|
||||
if (node.needsSaving()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -101,7 +101,7 @@ public class Item extends JSONElement {
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return (this.state == State.modified ? "*" : "")+name+" ("+id+")";
|
||||
return (needsSaving() ? "*" : "")+name+" ("+id+")";
|
||||
}
|
||||
|
||||
public static String getStaticDesc() {
|
||||
@@ -450,12 +450,14 @@ public class Item extends JSONElement {
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
if (this.category == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
this.category = (ItemCategory) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
} else {
|
||||
if (this.equip_effect != null && this.equip_effect.conditions != null) {
|
||||
for (ConditionEffect c : this.equip_effect.conditions) {
|
||||
if (c.condition == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
c.condition = (ActorCondition) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
}
|
||||
@@ -464,6 +466,7 @@ public class Item extends JSONElement {
|
||||
if (this.hit_effect != null && this.hit_effect.conditions_source != null) {
|
||||
for (TimedConditionEffect c : this.hit_effect.conditions_source) {
|
||||
if (c.condition == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
c.condition = (ActorCondition) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
}
|
||||
@@ -472,6 +475,7 @@ public class Item extends JSONElement {
|
||||
if (this.hit_effect != null && this.hit_effect.conditions_target != null) {
|
||||
for (TimedConditionEffect c : this.hit_effect.conditions_target) {
|
||||
if (c.condition == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
c.condition = (ActorCondition) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
}
|
||||
@@ -481,6 +485,7 @@ public class Item extends JSONElement {
|
||||
if (this.kill_effect != null && this.kill_effect.conditions_source != null) {
|
||||
for (TimedConditionEffect c : this.kill_effect.conditions_source) {
|
||||
if (c.condition == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
c.condition = (ActorCondition) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
}
|
||||
@@ -492,10 +497,12 @@ public class Item extends JSONElement {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Map toJson() {
|
||||
Map itemJson = new HashMap();
|
||||
Map itemJson = new LinkedHashMap();
|
||||
itemJson.put("id", this.id);
|
||||
if (this.icon_id != null) itemJson.put("iconID", this.icon_id);
|
||||
if (this.name != null) itemJson.put("name", this.name);
|
||||
if(this.display_type != null) itemJson.put("displaytype", this.display_type.toString());
|
||||
|
||||
if (this.has_manual_price != null) itemJson.put("hasManualPrice", this.has_manual_price);
|
||||
if (this.base_market_cost != null) itemJson.put("baseMarketCost", this.base_market_cost);
|
||||
if (this.category != null) {
|
||||
@@ -505,10 +512,10 @@ public class Item extends JSONElement {
|
||||
}
|
||||
if (this.description != null) itemJson.put("description", this.description);
|
||||
if (this.equip_effect != null) {
|
||||
Map equipEffectJson = new HashMap();
|
||||
Map equipEffectJson = new LinkedHashMap();
|
||||
itemJson.put("equipEffect", equipEffectJson);
|
||||
if (this.equip_effect.damage_boost_min != null || this.equip_effect.damage_boost_max != null) {
|
||||
Map damageJson = new HashMap();
|
||||
Map damageJson = new LinkedHashMap();
|
||||
equipEffectJson.put("increaseAttackDamage", damageJson);
|
||||
if (this.equip_effect.damage_boost_min != null) damageJson.put("min", this.equip_effect.damage_boost_min);
|
||||
else damageJson.put("min", 0);
|
||||
@@ -530,7 +537,7 @@ public class Item extends JSONElement {
|
||||
List conditionsJson = new ArrayList();
|
||||
equipEffectJson.put("addedConditions", conditionsJson);
|
||||
for (ConditionEffect condition : this.equip_effect.conditions) {
|
||||
Map conditionJson = new HashMap();
|
||||
Map conditionJson = new LinkedHashMap();
|
||||
conditionsJson.add(conditionJson);
|
||||
if (condition.condition != null) {
|
||||
conditionJson.put("condition", condition.condition.id);
|
||||
@@ -542,10 +549,10 @@ public class Item extends JSONElement {
|
||||
}
|
||||
}
|
||||
if (this.hit_effect != null) {
|
||||
Map hitEffectJson = new HashMap();
|
||||
Map hitEffectJson = new LinkedHashMap();
|
||||
itemJson.put("hitEffect", hitEffectJson);
|
||||
if (this.hit_effect.hp_boost_min != null || this.hit_effect.hp_boost_max != null) {
|
||||
Map hpJson = new HashMap();
|
||||
Map hpJson = new LinkedHashMap();
|
||||
hitEffectJson.put("increaseCurrentHP", hpJson);
|
||||
if (this.hit_effect.hp_boost_min != null) hpJson.put("min", this.hit_effect.hp_boost_min);
|
||||
else hpJson.put("min", 0);
|
||||
@@ -553,7 +560,7 @@ public class Item extends JSONElement {
|
||||
else hpJson.put("max", 0);
|
||||
}
|
||||
if (this.hit_effect.ap_boost_min != null || this.hit_effect.ap_boost_max != null) {
|
||||
Map apJson = new HashMap();
|
||||
Map apJson = new LinkedHashMap();
|
||||
hitEffectJson.put("increaseCurrentAP", apJson);
|
||||
if (this.hit_effect.ap_boost_min != null) apJson.put("min", this.hit_effect.ap_boost_min);
|
||||
else apJson.put("min", 0);
|
||||
@@ -564,7 +571,7 @@ public class Item extends JSONElement {
|
||||
List conditionsSourceJson = new ArrayList();
|
||||
hitEffectJson.put("conditionsSource", conditionsSourceJson);
|
||||
for (TimedConditionEffect condition : this.hit_effect.conditions_source) {
|
||||
Map conditionJson = new HashMap();
|
||||
Map conditionJson = new LinkedHashMap();
|
||||
conditionsSourceJson.add(conditionJson);
|
||||
if (condition.condition != null) {
|
||||
conditionJson.put("condition", condition.condition.id);
|
||||
@@ -580,7 +587,7 @@ public class Item extends JSONElement {
|
||||
List conditionsTargetJson = new ArrayList();
|
||||
hitEffectJson.put("conditionsTarget", conditionsTargetJson);
|
||||
for (TimedConditionEffect condition : this.hit_effect.conditions_target) {
|
||||
Map conditionJson = new HashMap();
|
||||
Map conditionJson = new LinkedHashMap();
|
||||
conditionsTargetJson.add(conditionJson);
|
||||
if (condition.condition != null) {
|
||||
conditionJson.put("condition", condition.condition.id);
|
||||
@@ -594,14 +601,14 @@ public class Item extends JSONElement {
|
||||
}
|
||||
}
|
||||
if (this.kill_effect != null) {
|
||||
Map killEffectJson = new HashMap();
|
||||
Map killEffectJson = new LinkedHashMap();
|
||||
if (this.category != null && this.category.action_type != null && this.category.action_type == ItemCategory.ActionType.equip) {
|
||||
itemJson.put("killEffect", killEffectJson);
|
||||
} else if (this.category != null && this.category.action_type != null && this.category.action_type == ItemCategory.ActionType.use) {
|
||||
itemJson.put("useEffect", killEffectJson);
|
||||
}
|
||||
if (this.kill_effect.hp_boost_min != null || this.kill_effect.hp_boost_max != null) {
|
||||
Map hpJson = new HashMap();
|
||||
Map hpJson = new LinkedHashMap();
|
||||
killEffectJson.put("increaseCurrentHP", hpJson);
|
||||
if (this.kill_effect.hp_boost_min != null) hpJson.put("min", this.kill_effect.hp_boost_min);
|
||||
else hpJson.put("min", 0);
|
||||
@@ -609,7 +616,7 @@ public class Item extends JSONElement {
|
||||
else hpJson.put("min", 0);
|
||||
}
|
||||
if (this.kill_effect.ap_boost_min != null || this.kill_effect.ap_boost_max != null) {
|
||||
Map apJson = new HashMap();
|
||||
Map apJson = new LinkedHashMap();
|
||||
killEffectJson.put("increaseCurrentAP", apJson);
|
||||
if (this.kill_effect.ap_boost_min != null) apJson.put("min", this.kill_effect.ap_boost_min);
|
||||
else apJson.put("min", 0);
|
||||
@@ -620,7 +627,7 @@ public class Item extends JSONElement {
|
||||
List conditionsSourceJson = new ArrayList();
|
||||
killEffectJson.put("conditionsSource", conditionsSourceJson);
|
||||
for (TimedConditionEffect condition : this.kill_effect.conditions_source) {
|
||||
Map conditionJson = new HashMap();
|
||||
Map conditionJson = new LinkedHashMap();
|
||||
conditionsSourceJson.add(conditionJson);
|
||||
if (condition.condition != null) {
|
||||
conditionJson.put("condition", condition.condition.id);
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -99,7 +99,7 @@ public class ItemCategory extends JSONElement {
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return (this.state == State.modified ? "*" : "")+name+" ("+id+")";
|
||||
return (needsSaving() ? "*" : "")+name+" ("+id+")";
|
||||
}
|
||||
|
||||
public static String getStaticDesc() {
|
||||
@@ -310,7 +310,7 @@ public class ItemCategory extends JSONElement {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Map toJson() {
|
||||
Map itemCatJson = new HashMap();
|
||||
Map itemCatJson = new LinkedHashMap();
|
||||
itemCatJson.put("id", this.id);
|
||||
if (this.name != null) itemCatJson.put("name", this.name);
|
||||
if (this.action_type != null) itemCatJson.put("actionType", this.action_type.toString());
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -95,7 +95,7 @@ public class NPC extends JSONElement {
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return (this.state == State.modified ? "*" : "")+name+" ("+id+")";
|
||||
return (needsSaving() ? "*" : "")+name+" ("+id+")";
|
||||
}
|
||||
|
||||
public static String getStaticDesc() {
|
||||
@@ -356,16 +356,19 @@ public class NPC extends JSONElement {
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
if (dialogue == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
this.dialogue = (Dialogue) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
} else {
|
||||
if (this.droplist == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
this.droplist = (Droplist) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
} else {
|
||||
if (this.hit_effect != null && this.hit_effect.conditions_source != null) {
|
||||
for (TimedConditionEffect tce : this.hit_effect.conditions_source) {
|
||||
if (tce.condition == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
tce.condition = (ActorCondition) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
}
|
||||
@@ -374,6 +377,7 @@ public class NPC extends JSONElement {
|
||||
if (this.hit_effect != null && this.hit_effect.conditions_target != null) {
|
||||
for (TimedConditionEffect tce : this.hit_effect.conditions_target) {
|
||||
if (tce.condition == oldOne) {
|
||||
oldOne.removeBacklink(this);
|
||||
tce.condition = (ActorCondition) newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
}
|
||||
@@ -386,7 +390,7 @@ public class NPC extends JSONElement {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Map toJson() {
|
||||
Map npcJson = new HashMap();
|
||||
Map npcJson = new LinkedHashMap();
|
||||
npcJson.put("id", this.id);
|
||||
if (this.name != null) npcJson.put("name", this.name);
|
||||
if (this.icon_id != null) npcJson.put("iconID", this.icon_id);
|
||||
@@ -397,7 +401,7 @@ public class NPC extends JSONElement {
|
||||
if (this.monster_class != null) npcJson.put("monsterClass", this.monster_class.toString());
|
||||
if (this.movement_type != null) npcJson.put("movementAggressionType", this.movement_type.toString());
|
||||
if (this.attack_damage_min != null || this.attack_damage_max != null) {
|
||||
Map adJson = new HashMap();
|
||||
Map adJson = new LinkedHashMap();
|
||||
npcJson.put("attackDamage", adJson);
|
||||
if (this.attack_damage_min != null) adJson.put("min", this.attack_damage_min);
|
||||
else adJson.put("min", 0);
|
||||
@@ -423,10 +427,10 @@ public class NPC extends JSONElement {
|
||||
if (this.block_chance != null) npcJson.put("blockChance", this.block_chance);
|
||||
if (this.damage_resistance != null) npcJson.put("damageResistance", this.damage_resistance);
|
||||
if (this.hit_effect != null) {
|
||||
Map hitEffectJson = new HashMap();
|
||||
Map hitEffectJson = new LinkedHashMap();
|
||||
npcJson.put("hitEffect", hitEffectJson);
|
||||
if (this.hit_effect.hp_boost_min != null || this.hit_effect.hp_boost_max != null) {
|
||||
Map hpJson = new HashMap();
|
||||
Map hpJson = new LinkedHashMap();
|
||||
hitEffectJson.put("increaseCurrentHP", hpJson);
|
||||
if (this.hit_effect.hp_boost_min != null) hpJson.put("min", this.hit_effect.hp_boost_min);
|
||||
else hpJson.put("min", 0);
|
||||
@@ -434,7 +438,7 @@ public class NPC extends JSONElement {
|
||||
else hpJson.put("max", 0);
|
||||
}
|
||||
if (this.hit_effect.ap_boost_min != null || this.hit_effect.ap_boost_max != null) {
|
||||
Map apJson = new HashMap();
|
||||
Map apJson = new LinkedHashMap();
|
||||
hitEffectJson.put("increaseCurrentAP", apJson);
|
||||
if (this.hit_effect.ap_boost_min != null) apJson.put("min", this.hit_effect.ap_boost_min);
|
||||
else apJson.put("min", 0);
|
||||
@@ -445,7 +449,7 @@ public class NPC extends JSONElement {
|
||||
List conditionsSourceJson = new ArrayList();
|
||||
hitEffectJson.put("conditionsSource", conditionsSourceJson);
|
||||
for (TimedConditionEffect condition : this.hit_effect.conditions_source) {
|
||||
Map conditionJson = new HashMap();
|
||||
Map conditionJson = new LinkedHashMap();
|
||||
conditionsSourceJson.add(conditionJson);
|
||||
if (condition.condition != null) {
|
||||
conditionJson.put("condition", condition.condition.id);
|
||||
@@ -461,7 +465,7 @@ public class NPC extends JSONElement {
|
||||
List conditionsTargetJson = new ArrayList();
|
||||
hitEffectJson.put("conditionsTarget", conditionsTargetJson);
|
||||
for (TimedConditionEffect condition : this.hit_effect.conditions_target) {
|
||||
Map conditionJson = new HashMap();
|
||||
Map conditionJson = new LinkedHashMap();
|
||||
conditionsTargetJson.add(conditionJson);
|
||||
if (condition.condition != null) {
|
||||
conditionJson.put("condition", condition.condition.id);
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -30,25 +30,9 @@ public class Quest extends JSONElement {
|
||||
public Integer visible_in_log = null;
|
||||
public List<QuestStage> stages = null;
|
||||
|
||||
public static class QuestStage implements Cloneable {
|
||||
public Integer progress = null;
|
||||
public String log_text = null;
|
||||
public Integer exp_reward = null;
|
||||
public Integer finishes_quest = null;
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return (this.state == State.modified ? "*" : "")+name+" ("+id+")";
|
||||
return (needsSaving() ? "*" : "")+name+" ("+id+")";
|
||||
}
|
||||
|
||||
public static String getStaticDesc() {
|
||||
@@ -105,6 +89,8 @@ public class Quest extends JSONElement {
|
||||
Quest quest = new Quest();
|
||||
quest.id = (String) questJson.get("id");
|
||||
quest.name = (String) questJson.get("name");
|
||||
//Quests have to be parsed to have their stages initialized.
|
||||
quest.parse(questJson);
|
||||
return quest;
|
||||
}
|
||||
|
||||
@@ -117,15 +103,12 @@ public class Quest extends JSONElement {
|
||||
this.stages = new ArrayList<QuestStage>();
|
||||
for (Object questStageJsonObj : questStagesJson) {
|
||||
Map questStageJson = (Map)questStageJsonObj;
|
||||
QuestStage questStage = new QuestStage();
|
||||
questStage.progress = JSONElement.getInteger((Number) questStageJson.get("progress"));
|
||||
questStage.log_text = (String) questStageJson.get("logText");
|
||||
questStage.exp_reward = JSONElement.getInteger((Number) questStageJson.get("rewardExperience"));
|
||||
questStage.finishes_quest = JSONElement.getInteger((Number) questStageJson.get("finishesQuest"));
|
||||
QuestStage questStage = new QuestStage(this);
|
||||
questStage.parse(questStageJson);
|
||||
this.stages.add(questStage);
|
||||
}
|
||||
}
|
||||
|
||||
this.state = State.parsed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -142,6 +125,9 @@ public class Quest extends JSONElement {
|
||||
return;
|
||||
}
|
||||
|
||||
for (QuestStage stage : stages) {
|
||||
stage.link();
|
||||
}
|
||||
//Nothing to link to :D
|
||||
this.state = State.linked;
|
||||
}
|
||||
@@ -164,9 +150,9 @@ public class Quest extends JSONElement {
|
||||
clone.name = this.name;
|
||||
clone.visible_in_log = this.visible_in_log;
|
||||
if (this.stages != null) {
|
||||
clone.stages = new ArrayList<Quest.QuestStage>();
|
||||
clone.stages = new ArrayList<QuestStage>();
|
||||
for (QuestStage stage : this.stages){
|
||||
clone.stages.add((QuestStage) stage.clone());
|
||||
clone.stages.add((QuestStage) stage.clone(clone));
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
@@ -180,7 +166,7 @@ public class Quest extends JSONElement {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Map toJson() {
|
||||
Map questJson = new HashMap();
|
||||
Map questJson = new LinkedHashMap();
|
||||
questJson.put("id", this.id);
|
||||
if (this.name != null) questJson.put("name", this.name);
|
||||
if (this.visible_in_log != null) questJson.put("showInLog", this.visible_in_log);
|
||||
@@ -188,12 +174,7 @@ public class Quest extends JSONElement {
|
||||
List stagesJson = new ArrayList();
|
||||
questJson.put("stages", stagesJson);
|
||||
for (QuestStage stage : this.stages) {
|
||||
Map stageJson = new HashMap();
|
||||
stagesJson.add(stageJson);
|
||||
if (stage.progress != null) stageJson.put("progress", stage.progress);
|
||||
if (stage.log_text != null) stageJson.put("logText", stage.log_text);
|
||||
if (stage.exp_reward != null) stageJson.put("rewardExperience", stage.exp_reward);
|
||||
if (stage.finishes_quest != null) stageJson.put("finishesQuest", stage.finishes_quest);
|
||||
stagesJson.add(stage.toJson());
|
||||
}
|
||||
}
|
||||
return questJson;
|
||||
@@ -204,5 +185,14 @@ public class Quest extends JSONElement {
|
||||
public String getProjectFilename() {
|
||||
return "questlist_"+getProject().name+".json";
|
||||
}
|
||||
|
||||
public QuestStage getStage(Integer stageId) {
|
||||
for (QuestStage stage : stages) {
|
||||
if (stage.progress.equals(stageId)) {
|
||||
return stage;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
103
src/com/gpl/rpg/atcontentstudio/model/gamedata/QuestStage.java
Normal file
@@ -0,0 +1,103 @@
|
||||
package com.gpl.rpg.atcontentstudio.model.gamedata;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
|
||||
public class QuestStage extends JSONElement {
|
||||
|
||||
private static final long serialVersionUID = 8313645819951513431L;
|
||||
|
||||
public Integer progress = null;
|
||||
public String log_text = null;
|
||||
public Integer exp_reward = null;
|
||||
public Integer finishes_quest = null;
|
||||
|
||||
public QuestStage(Quest parent){
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public QuestStage clone(Quest cloneParent) {
|
||||
QuestStage clone = new QuestStage(cloneParent);
|
||||
clone.progress = progress != null ? new Integer(progress) : null;
|
||||
clone.log_text = log_text != null ? new String(log_text) : null;
|
||||
clone.exp_reward = exp_reward != null ? new Integer(exp_reward) : null;
|
||||
clone.finishes_quest = finishes_quest != null ? new Integer(finishes_quest) : null;
|
||||
clone.id = this.id;
|
||||
return clone;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void parse(Map jsonObj) {
|
||||
progress = JSONElement.getInteger((Number) jsonObj.get("progress"));
|
||||
this.id = ((Quest)parent).id+":"+progress;
|
||||
log_text = (String) jsonObj.get("logText");
|
||||
exp_reward = JSONElement.getInteger((Number) jsonObj.get("rewardExperience"));
|
||||
finishes_quest = JSONElement.getInteger((Number) jsonObj.get("finishesQuest"));
|
||||
state = State.parsed;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Map toJson() {
|
||||
Map stageJson = new LinkedHashMap();
|
||||
if (progress != null) stageJson.put("progress", progress);
|
||||
if (log_text != null) stageJson.put("logText", log_text);
|
||||
if (exp_reward != null) stageJson.put("rewardExperience", exp_reward);
|
||||
if (finishes_quest != null) stageJson.put("finishesQuest", finishes_quest);
|
||||
return stageJson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return progress+" - "+(exp_reward != null ? "["+exp_reward+"XP]" : "")+((finishes_quest != null) && (finishes_quest == 1) ? "[END]" : "")+log_text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void link() {
|
||||
if (this.state == State.created || this.state == State.modified || this.state == State.saved) {
|
||||
//This type of state is unrelated to parsing/linking.
|
||||
return;
|
||||
}
|
||||
if (this.state == State.init) {
|
||||
//Not parsed yet.
|
||||
this.parse();
|
||||
} else if (this.state == State.linked) {
|
||||
//Already linked.
|
||||
return;
|
||||
}
|
||||
|
||||
//Nothing to link to :D
|
||||
this.state = State.linked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
// Nothing to link to.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProjectFilename() {
|
||||
return ((Quest)parent).getProjectFilename();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameDataElement clone() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getIcon() {
|
||||
return DefaultIcons.getQuestIcon();
|
||||
}
|
||||
|
||||
public Image getImage() {
|
||||
return DefaultIcons.getQuestImage();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.gpl.rpg.atcontentstudio.model.gamedata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -13,7 +13,7 @@ public class Requirement extends JSONElement {
|
||||
|
||||
private static final long serialVersionUID = 7295593297142310955L;
|
||||
|
||||
private static Map<RequirementType, List<RequirementType>> COMPATIBLE_TYPES = new HashMap<RequirementType, List<RequirementType>>();
|
||||
private static Map<RequirementType, List<RequirementType>> COMPATIBLE_TYPES = new LinkedHashMap<RequirementType, List<RequirementType>>();
|
||||
|
||||
static {
|
||||
List<RequirementType> questTypes = new ArrayList<RequirementType>();
|
||||
@@ -112,6 +112,12 @@ public class Requirement extends JSONElement {
|
||||
case questLatestProgress:
|
||||
case questProgress:
|
||||
this.required_obj = proj.getQuest(required_obj_id);
|
||||
if (this.required_obj != null && this.required_value != null) {
|
||||
QuestStage stage = ((Quest)this.required_obj).getStage(this.required_value);
|
||||
if (stage != null) {
|
||||
stage.addBacklink((GameDataElement) this.parent);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case consumedBonemeals:
|
||||
case skillLevel:
|
||||
@@ -120,6 +126,7 @@ public class Requirement extends JSONElement {
|
||||
break;
|
||||
}
|
||||
if (this.required_obj != null) this.required_obj.addBacklink((GameDataElement) this.parent);
|
||||
this.state = State.linked;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -145,8 +152,15 @@ public class Requirement extends JSONElement {
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
if (this.required_obj == oldOne) {
|
||||
oldOne.removeBacklink((GameDataElement) this.parent);
|
||||
this.required_obj = newOne;
|
||||
if (newOne != null) newOne.addBacklink(this);
|
||||
if (newOne != null) newOne.addBacklink((GameDataElement) this.parent);
|
||||
}
|
||||
if (oldOne instanceof QuestStage) {
|
||||
if (this.required_obj != null && this.required_obj.equals(oldOne.parent) && this.required_value != null && this.required_value.equals(((QuestStage) oldOne).progress)) {
|
||||
oldOne.removeBacklink((GameDataElement) this.parent);
|
||||
if (newOne != null) newOne.addBacklink((GameDataElement) this.parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
|
||||
@@ -29,8 +29,9 @@ public class ContainerArea extends MapObject {
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
if (oldOne == droplist) {
|
||||
oldOne.removeBacklink(parentMap);
|
||||
droplist = (Droplist) newOne;
|
||||
newOne.addBacklink(parentMap);
|
||||
if (newOne != null) newOne.addBacklink(parentMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,23 +19,23 @@ public class KeyArea extends MapObject {
|
||||
String requireType = obj.getProperties().getProperty("requireType");
|
||||
String requireId = obj.getProperties().getProperty("requireId");
|
||||
String requireValue = obj.getProperties().getProperty("requireValue");
|
||||
oldSchoolRequirement = false;
|
||||
if (requireId == null) {
|
||||
String[] fields = obj.getName().split(":");
|
||||
if (fields.length == 2) {
|
||||
requireType = Requirement.RequirementType.questProgress.toString();
|
||||
requireValue = fields[1];
|
||||
requireId = fields[0];
|
||||
oldSchoolRequirement = true;
|
||||
} else if (fields.length == 3) {
|
||||
requireValue = fields[2];
|
||||
requireType = fields[0];
|
||||
requireId = fields[1];
|
||||
oldSchoolRequirement = true;
|
||||
}
|
||||
oldSchoolRequirement = true;
|
||||
} else {
|
||||
oldSchoolRequirement = false;
|
||||
}
|
||||
requirement = new Requirement();
|
||||
requirement.type = Requirement.RequirementType.valueOf(requireType);
|
||||
if (requireType != null) requirement.type = Requirement.RequirementType.valueOf(requireType);
|
||||
requirement.required_obj_id = requireId;
|
||||
if (requireValue != null) requirement.required_value = Integer.parseInt(requireValue);
|
||||
requirement.state = GameDataElement.State.parsed;
|
||||
@@ -60,8 +60,9 @@ public class KeyArea extends MapObject {
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
if (oldOne == dialogue) {
|
||||
oldOne.removeBacklink(parentMap);
|
||||
dialogue = (Dialogue) newOne;
|
||||
newOne.addBacklink(parentMap);
|
||||
if (newOne != null) newOne.addBacklink(parentMap);
|
||||
}
|
||||
requirement.elementChanged(oldOne, newOne);
|
||||
}
|
||||
@@ -77,7 +78,9 @@ public class KeyArea extends MapObject {
|
||||
if (oldSchoolRequirement && Requirement.RequirementType.questProgress.equals(requirement.type) && (requirement.negated == null || !requirement.negated)) {
|
||||
tmxObject.setName(requirement.required_obj_id+":"+Integer.toString(requirement.required_value));
|
||||
} else {
|
||||
tmxObject.getProperties().setProperty("requireType", requirement.type.toString());
|
||||
if (requirement.type != null) {
|
||||
tmxObject.getProperties().setProperty("requireType", requirement.type.toString());
|
||||
}
|
||||
if (requirement.required_obj != null) {
|
||||
tmxObject.getProperties().setProperty("requireId", requirement.required_obj.id);
|
||||
} else if (requirement.required_obj_id != null) {
|
||||
|
||||
@@ -37,8 +37,9 @@ public class MapChange extends MapObject {
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
if (oldOne == map) {
|
||||
oldOne.removeBacklink(parentMap);
|
||||
map = (TMXMap) newOne;
|
||||
newOne.addBacklink(parentMap);
|
||||
if (newOne != null) newOne.addBacklink(parentMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,12 +13,18 @@ public class MapObjectGroup {
|
||||
public String name;
|
||||
public boolean visible;
|
||||
public List<MapObject> mapObjects = new ArrayList<MapObject>();
|
||||
public Boolean active;
|
||||
|
||||
public MapObjectGroup(tiled.core.ObjectGroup layer, TMXMap map) {
|
||||
this.tmxGroup = layer;
|
||||
this.name = layer.getName();
|
||||
this.visible = layer.isVisible();
|
||||
this.parentMap = map;
|
||||
if (layer.getProperties().get("active") != null) {
|
||||
active = new Boolean(((String) layer.getProperties().get("active")));
|
||||
} else {
|
||||
active = true;
|
||||
}
|
||||
for (tiled.core.MapObject obj : layer.getObjectsList()) {
|
||||
mapObjects.add(MapObject.buildObject(obj, map));
|
||||
}
|
||||
@@ -44,6 +50,9 @@ public class MapObjectGroup {
|
||||
}
|
||||
tmxGroup.setVisible(visible);
|
||||
tmxGroup.setName(name);
|
||||
if (!active) {
|
||||
tmxGroup.getProperties().put("active", Boolean.toString(active));
|
||||
}
|
||||
for (MapObject object : mapObjects) {
|
||||
tmxGroup.addObject(object.toTmxObject());
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.gpl.rpg.atcontentstudio.model.maps;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.Requirement;
|
||||
@@ -14,7 +12,7 @@ import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
public class ReplaceArea extends MapObject {
|
||||
|
||||
public Requirement requirement = null;
|
||||
public boolean oldSchoolRequirement = true;
|
||||
public boolean oldSchoolRequirement = false;
|
||||
|
||||
public List<ReplaceArea.Replacement> replacements = null;
|
||||
|
||||
@@ -28,14 +26,12 @@ public class ReplaceArea extends MapObject {
|
||||
// requireType = Requirement.RequirementType.questProgress.toString();
|
||||
requireValue = fields[1];
|
||||
requireId = fields[0];
|
||||
oldSchoolRequirement = true;
|
||||
} /*else if (fields.length == 3) {
|
||||
requireValue = fields[2];
|
||||
requireType = fields[0];
|
||||
requireId = fields[1];
|
||||
}*/
|
||||
oldSchoolRequirement = true;
|
||||
} else {
|
||||
oldSchoolRequirement = false;
|
||||
}
|
||||
requirement = new Requirement();
|
||||
//Replace areas only support questProgress requirements ATM
|
||||
@@ -47,7 +43,8 @@ public class ReplaceArea extends MapObject {
|
||||
|
||||
|
||||
for (Object s : obj.getProperties().keySet()) {
|
||||
if (replacements == null) replacements = new LinkedList<ReplaceArea.Replacement>();
|
||||
if (!TMXMap.isPaintedLayerName(s.toString())) continue;
|
||||
if (replacements == null) replacements = new ArrayList<ReplaceArea.Replacement>();
|
||||
replacements.add(new Replacement(s.toString(), obj.getProperties().getProperty(s.toString())));
|
||||
}
|
||||
|
||||
@@ -76,7 +73,7 @@ public class ReplaceArea extends MapObject {
|
||||
}
|
||||
|
||||
public void addReplacement(ReplaceArea.Replacement repl) {
|
||||
if (replacements == null) replacements = new LinkedList<ReplaceArea.Replacement>();
|
||||
if (replacements == null) replacements = new ArrayList<ReplaceArea.Replacement>();
|
||||
replacements.add(repl);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,9 @@ public class ScriptArea extends MapObject {
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
if (oldOne == dialogue) {
|
||||
oldOne.removeBacklink(parentMap);
|
||||
dialogue = (Dialogue) newOne;
|
||||
newOne.addBacklink(parentMap);
|
||||
if (newOne != null) newOne.addBacklink(parentMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,9 @@ public class SignArea extends MapObject {
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
if (oldOne == dialogue) {
|
||||
oldOne.removeBacklink(parentMap);
|
||||
dialogue = (Dialogue) newOne;
|
||||
newOne.addBacklink(parentMap);
|
||||
if (newOne != null) newOne.addBacklink(parentMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ public class SpawnArea extends MapObject {
|
||||
public int quantity = 1;
|
||||
public int spawnchance = 10;
|
||||
public boolean active = true;
|
||||
public String spawngroup_id;
|
||||
public List<NPC> spawnGroup = new ArrayList<NPC>();
|
||||
|
||||
public SpawnArea(tiled.core.MapObject obj) {
|
||||
@@ -25,12 +26,17 @@ public class SpawnArea extends MapObject {
|
||||
if (obj.getProperties().getProperty("active") != null) {
|
||||
this.active = Boolean.parseBoolean(obj.getProperties().getProperty("active"));
|
||||
}
|
||||
if (obj.getProperties().getProperty("spawngroup") != null) {
|
||||
this.spawngroup_id = obj.getProperties().getProperty("spawngroup");
|
||||
} else if (obj.getName() != null ){
|
||||
this.spawngroup_id = obj.getName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void link() {
|
||||
if (name != null) {
|
||||
spawnGroup = parentMap.getProject().getSpawnGroup(name);
|
||||
if (spawngroup_id != null) {
|
||||
spawnGroup = parentMap.getProject().getSpawnGroup(spawngroup_id);
|
||||
} else {
|
||||
spawnGroup = new ArrayList<NPC>();
|
||||
}
|
||||
@@ -58,13 +64,17 @@ public class SpawnArea extends MapObject {
|
||||
}
|
||||
}
|
||||
if (replacedIndex >= 0) {
|
||||
oldOne.removeBacklink(parentMap);
|
||||
spawnGroup.set(replacedIndex, (NPC) newOne);
|
||||
newOne.addBacklink(parentMap);
|
||||
if (newOne != null) newOne.addBacklink(parentMap);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void savePropertiesInTmxObject(tiled.core.MapObject tmxObject) {
|
||||
if (spawngroup_id != null) {
|
||||
tmxObject.getProperties().setProperty("spawngroup", spawngroup_id);
|
||||
}
|
||||
if (quantity != 1) {
|
||||
tmxObject.getProperties().setProperty("quantity", Integer.toString(quantity));
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
@@ -21,11 +22,12 @@ import tiled.io.TMXMapWriter;
|
||||
import com.gpl.rpg.atcontentstudio.Notification;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource;
|
||||
import com.gpl.rpg.atcontentstudio.model.SaveEvent;
|
||||
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.SaveEvent;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
|
||||
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
|
||||
@@ -38,6 +40,18 @@ public class TMXMap extends GameDataElement {
|
||||
public static final String ABOVE_LAYER_NAME = "Above";
|
||||
public static final String WALKABLE_LAYER_NAME = "Walkable";
|
||||
|
||||
public enum ColorFilter {
|
||||
none,
|
||||
black20,
|
||||
black40,
|
||||
black60,
|
||||
black80,
|
||||
invert,
|
||||
bw,
|
||||
redtint,
|
||||
greentint,
|
||||
bluetint
|
||||
}
|
||||
|
||||
public File tmxFile = null;
|
||||
public tiled.core.Map tmxMap = null;
|
||||
@@ -46,8 +60,10 @@ public class TMXMap extends GameDataElement {
|
||||
|
||||
public ProjectTreeNode parent;
|
||||
public Integer outside = null;
|
||||
public ColorFilter colorFilter = null;
|
||||
|
||||
public boolean writable = false;
|
||||
public boolean changedOnDisk = false;
|
||||
public int dismissNextChangeNotif = 0;
|
||||
|
||||
public TMXMap(TMXMapSet parent, File f) {
|
||||
this.parent = parent;
|
||||
@@ -62,8 +78,11 @@ public class TMXMap extends GameDataElement {
|
||||
usedSpritesheets = new HashSet<Spritesheet>();
|
||||
try {
|
||||
tmxMap = new TMXMapReader().readMap(tmxFile.getAbsolutePath(), this);
|
||||
if (tmxMap.getProperties().get("outside") != null) {
|
||||
outside = new Integer(((String) tmxMap.getProperties().get("outside")));
|
||||
if (tmxMap.getProperties().get("outdoors") != null) {
|
||||
outside = new Integer(((String) tmxMap.getProperties().get("outdoors")));
|
||||
}
|
||||
if (tmxMap.getProperties().get("colorfilter") != null) {
|
||||
colorFilter = ColorFilter.valueOf(((String) tmxMap.getProperties().get("colorfilter")));
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Notification.addError("Impossible to load TMX map file "+tmxFile.getAbsolutePath());
|
||||
@@ -97,8 +116,11 @@ public class TMXMap extends GameDataElement {
|
||||
try {
|
||||
clone.usedSpritesheets = new HashSet<Spritesheet>();
|
||||
clone.tmxMap = new TMXMapReader().readMap(new StringReader(this.toXml()), clone);
|
||||
if (clone.tmxMap.getProperties().get("outside") != null) {
|
||||
clone.outside = new Integer(((String) clone.tmxMap.getProperties().get("outside")));
|
||||
if (clone.tmxMap.getProperties().get("outdoors") != null) {
|
||||
clone.outside = new Integer(((String) clone.tmxMap.getProperties().get("outdoors")));
|
||||
}
|
||||
if (clone.tmxMap.getProperties().get("colorfilter") != null) {
|
||||
clone.colorFilter = ColorFilter.valueOf(((String) tmxMap.getProperties().get("colorfilter")));
|
||||
}
|
||||
for (tiled.core.MapLayer layer : clone.tmxMap.getLayers()) {
|
||||
if (layer instanceof tiled.core.ObjectGroup) {
|
||||
@@ -106,6 +128,7 @@ public class TMXMap extends GameDataElement {
|
||||
clone.groups = new ArrayList<MapObjectGroup>();
|
||||
}
|
||||
MapObjectGroup group = new MapObjectGroup((tiled.core.ObjectGroup) layer, this);
|
||||
group.link();
|
||||
clone.groups.add(group);
|
||||
}
|
||||
}
|
||||
@@ -178,7 +201,7 @@ public class TMXMap extends GameDataElement {
|
||||
}
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return (this.state == State.modified ? "*" : "")+id;
|
||||
return (needsSaving() ? "*" : "")+id;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -210,6 +233,17 @@ public class TMXMap extends GameDataElement {
|
||||
}
|
||||
|
||||
public String toXml() {
|
||||
if (outside != null && outside == 1) {
|
||||
tmxMap.getProperties().put("outdoors", Integer.toString(outside));
|
||||
} else {
|
||||
tmxMap.getProperties().remove("outdoors");
|
||||
}
|
||||
if (colorFilter != null) {
|
||||
tmxMap.getProperties().put("colorfilter", colorFilter.toString());
|
||||
} else {
|
||||
tmxMap.getProperties().remove("colorfilter");
|
||||
}
|
||||
|
||||
for (MapObjectGroup group : groups) {
|
||||
group.pushBackToTiledProperties();
|
||||
if (!tmxMap.containsLayer(group.tmxGroup)) {
|
||||
@@ -239,11 +273,15 @@ public class TMXMap extends GameDataElement {
|
||||
|
||||
public void save() {
|
||||
if (writable) {
|
||||
String xml = toXml();
|
||||
try {
|
||||
//TODO: check in fileutils, to test the workspace's filesystem once at startup, and figure out how many of these can occur, instead of hard-coded '2'
|
||||
dismissNextChangeNotif += 2;
|
||||
FileWriter w = new FileWriter(tmxFile);
|
||||
w.write(toXml());
|
||||
w.write(xml);
|
||||
w.close();
|
||||
this.state = State.saved;
|
||||
changedOnDisk = false;
|
||||
Notification.addSuccess("TMX file "+tmxFile.getAbsolutePath()+" saved.");
|
||||
} catch (IOException e) {
|
||||
Notification.addError("Error while writing TMX file "+tmxFile.getAbsolutePath()+" : "+e.getMessage());
|
||||
@@ -278,9 +316,11 @@ public class TMXMap extends GameDataElement {
|
||||
if (this.state == GameDataElement.State.init) {
|
||||
parse();
|
||||
}
|
||||
if (this.state == GameDataElement.State.parsed || this.state == GameDataElement.State.created) {
|
||||
for (MapObjectGroup group : groups) {
|
||||
group.link();
|
||||
if (this.state == GameDataElement.State.parsed) {
|
||||
if (groups != null) {
|
||||
for (MapObjectGroup group : groups) {
|
||||
group.link();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,5 +400,77 @@ public class TMXMap extends GameDataElement {
|
||||
ABOVE_LAYER_NAME.equalsIgnoreCase(name) ||
|
||||
WALKABLE_LAYER_NAME.equalsIgnoreCase(name);
|
||||
}
|
||||
|
||||
|
||||
public void reload() {
|
||||
tmxMap = null;
|
||||
for (Spritesheet s : usedSpritesheets) {
|
||||
s.elementChanged(this, null);
|
||||
}
|
||||
usedSpritesheets.clear();
|
||||
for (MapObjectGroup g : groups) {
|
||||
for (MapObject o : g.mapObjects) {
|
||||
if (o instanceof ContainerArea) {
|
||||
if (((ContainerArea)o).droplist != null) ((ContainerArea)o).droplist.elementChanged(this, null);
|
||||
} else if (o instanceof KeyArea) {
|
||||
if (((KeyArea)o).dialogue != null) ((KeyArea)o).dialogue.elementChanged(this, null);
|
||||
if (((KeyArea)o).requirement != null && ((KeyArea)o).requirement.required_obj != null) ((KeyArea)o).requirement.required_obj.elementChanged(this, null);
|
||||
} else if (o instanceof MapChange) {
|
||||
if (((MapChange)o).map != null) ((MapChange)o).map.elementChanged(this, null);
|
||||
} else if (o instanceof ReplaceArea) {
|
||||
if (((ReplaceArea)o).requirement != null && ((ReplaceArea)o).requirement.required_obj != null) ((ReplaceArea)o).requirement.required_obj.elementChanged(this, null);
|
||||
} else if (o instanceof RestArea) {
|
||||
} else if (o instanceof ScriptArea) {
|
||||
if (((ScriptArea)o).dialogue != null) ((ScriptArea)o).dialogue.elementChanged(this, null);
|
||||
} else if (o instanceof SignArea) {
|
||||
if (((SignArea)o).dialogue != null) ((SignArea)o).dialogue.elementChanged(this, null);
|
||||
} else if (o instanceof SpawnArea) {
|
||||
if (((SpawnArea)o).spawnGroup != null) {
|
||||
for (NPC n : ((SpawnArea)o).spawnGroup) {
|
||||
n.elementChanged(this, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
groups.clear();
|
||||
outside = null;
|
||||
colorFilter = null;
|
||||
|
||||
state = GameDataElement.State.init;
|
||||
this.link();
|
||||
|
||||
changedOnDisk = false;
|
||||
for (MapChangedOnDiskListener l : listeners) {
|
||||
l.mapReloaded();
|
||||
}
|
||||
}
|
||||
|
||||
public void mapChangedOnDisk() {
|
||||
if (dismissNextChangeNotif > 0) {
|
||||
dismissNextChangeNotif--;
|
||||
} else {
|
||||
changedOnDisk = true;
|
||||
for (MapChangedOnDiskListener l : listeners) {
|
||||
l.mapChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface MapChangedOnDiskListener {
|
||||
public void mapChanged();
|
||||
public void mapReloaded();
|
||||
}
|
||||
|
||||
private List<MapChangedOnDiskListener> listeners = new CopyOnWriteArrayList<TMXMap.MapChangedOnDiskListener>();
|
||||
|
||||
public void addMapChangedOnDiskListener(MapChangedOnDiskListener l) {
|
||||
listeners.add(l);
|
||||
}
|
||||
|
||||
public void removeMapChangedOnDiskListener(MapChangedOnDiskListener l) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,14 @@ package com.gpl.rpg.atcontentstudio.model.maps;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardWatchEventKinds;
|
||||
import java.nio.file.WatchEvent;
|
||||
import java.nio.file.WatchKey;
|
||||
import java.nio.file.WatchService;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -10,18 +18,27 @@ import java.util.List;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.Notification;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
|
||||
import com.gpl.rpg.atcontentstudio.model.Project;
|
||||
import com.gpl.rpg.atcontentstudio.model.Project.ResourceSet;
|
||||
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
import com.gpl.rpg.atcontentstudio.utils.FileUtils;
|
||||
|
||||
public class TMXMapSet implements ProjectTreeNode {
|
||||
|
||||
public static final String DEFAULT_REL_PATH_IN_SOURCE = "res/xml/";
|
||||
public static final String DEFAULT_REL_PATH_IN_PROJECT = "maps/";
|
||||
public static final String DEFAULT_REL_PATH_IN_SOURCE = "res"+File.separator+"xml"+File.separator;
|
||||
public static final String DEFAULT_REL_PATH_IN_PROJECT = "maps"+File.separator;
|
||||
public static final String DEFAULT_REL_PATH_TO_DRAWABLE = ".."+File.separator+"drawable"+File.separator;
|
||||
|
||||
public static final String GAME_MAPS_ARRAY_NAME = "loadresource_maps";
|
||||
public static final String DEBUG_SUFFIX = "_debug";
|
||||
public static final String RESOURCE_PREFIX = "@xml/";
|
||||
public static final String FILENAME_SUFFIX = ".tmx";
|
||||
|
||||
public File mapFolder = null;
|
||||
public List<TMXMap> tmxMaps;
|
||||
|
||||
@@ -29,16 +46,34 @@ public class TMXMapSet implements ProjectTreeNode {
|
||||
|
||||
public TMXMapSet(GameSource source) {
|
||||
this.parent = source;
|
||||
if (source.type == GameSource.Type.source) this.mapFolder = new File(source.baseFolder, DEFAULT_REL_PATH_IN_SOURCE);
|
||||
if (source.type == GameSource.Type.source) {
|
||||
this.mapFolder = new File(source.baseFolder, DEFAULT_REL_PATH_IN_SOURCE);
|
||||
}
|
||||
else if (source.type == GameSource.Type.created | source.type == GameSource.Type.altered) {
|
||||
this.mapFolder = new File(source.baseFolder, DEFAULT_REL_PATH_IN_PROJECT);
|
||||
if (!this.mapFolder.exists()) {
|
||||
this.mapFolder.mkdirs();
|
||||
}
|
||||
FileUtils.makeSymlink(getProject().baseContent.gameSprites.drawableFolder, new File(mapFolder.getAbsolutePath()+File.separator+DEFAULT_REL_PATH_TO_DRAWABLE));
|
||||
}
|
||||
this.tmxMaps = new ArrayList<TMXMap>();
|
||||
|
||||
if (this.mapFolder != null) {
|
||||
if (source.type == GameSource.Type.source && (source.parent.sourceSetToUse == ResourceSet.debugData || source.parent.sourceSetToUse == ResourceSet.gameData)) {
|
||||
String suffix = (source.parent.sourceSetToUse == ResourceSet.debugData) ? DEBUG_SUFFIX : "";
|
||||
|
||||
if (source.referencedSourceFiles.get(GAME_MAPS_ARRAY_NAME+suffix) != null) {
|
||||
for (String resource : source.referencedSourceFiles.get(GAME_MAPS_ARRAY_NAME+suffix)) {
|
||||
File f = new File(mapFolder, resource.replaceAll(RESOURCE_PREFIX, "")+FILENAME_SUFFIX);
|
||||
if (f.exists()) {
|
||||
TMXMap map = new TMXMap(this, f);
|
||||
tmxMaps.add(map);
|
||||
} else {
|
||||
Notification.addWarn("Unable to locate resource "+resource+" in the game source for project "+getProject().name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (this.mapFolder != null) {
|
||||
for (File f : this.mapFolder.listFiles()) {
|
||||
if (f.getName().endsWith(".tmx") || f.getName().endsWith(".TMX")) {
|
||||
TMXMap map = new TMXMap(this, f);
|
||||
@@ -55,6 +90,43 @@ public class TMXMapSet implements ProjectTreeNode {
|
||||
return o1.id.compareTo(o2.id);
|
||||
}
|
||||
});
|
||||
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) {
|
||||
public void run() {
|
||||
WatchService watchService;
|
||||
|
||||
while(getProject().open) {
|
||||
try {
|
||||
watchService = FileSystems.getDefault().newWatchService();
|
||||
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();
|
||||
}
|
||||
}
|
||||
if(!wk.reset()) {
|
||||
watchService.close();
|
||||
break validService;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
watcher.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,7 +185,7 @@ public class TMXMapSet implements ProjectTreeNode {
|
||||
}
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return "TMX Maps";
|
||||
return (needsSaving() ? "*" : "")+"TMX Maps";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -188,4 +260,12 @@ public class TMXMapSet implements ProjectTreeNode {
|
||||
return tmxMaps.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
for (ProjectTreeNode node : tmxMaps) {
|
||||
if (node.needsSaving()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -36,6 +35,7 @@ import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
|
||||
import com.gpl.rpg.atcontentstudio.model.Project;
|
||||
@@ -174,7 +174,7 @@ public class Worldmap extends ArrayList<WorldmapSegment> implements ProjectTreeN
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return "Worldmap";
|
||||
return (needsSaving() ? "*" : "")+"Worldmap";
|
||||
}
|
||||
@Override
|
||||
public void notifyCreated() {
|
||||
@@ -223,6 +223,7 @@ public class Worldmap extends ArrayList<WorldmapSegment> implements ProjectTreeN
|
||||
|
||||
for (WorldmapSegment segment : this) {
|
||||
root.appendChild(segment.toXmlElement(doc));
|
||||
segment.state = GameDataElement.State.saved;
|
||||
}
|
||||
|
||||
saveDocToFile(doc, worldmapFile);
|
||||
@@ -278,6 +279,13 @@ public class Worldmap extends ArrayList<WorldmapSegment> implements ProjectTreeN
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
for (ProjectTreeNode node : this) {
|
||||
if (node.needsSaving()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,11 +3,8 @@ package com.gpl.rpg.atcontentstudio.model.maps;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -27,6 +24,7 @@ import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
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;
|
||||
@@ -35,6 +33,8 @@ public class WorldmapSegment extends GameDataElement {
|
||||
|
||||
private static final long serialVersionUID = 2658610076889592723L;
|
||||
|
||||
public static final String TEMP_LABEL_KEY = "ATCS_INTERNAL_TEMPORARY_KEY_FOR_LABEL";
|
||||
|
||||
public int segmentX;
|
||||
public int segmentY;
|
||||
public Map<String, Point> mapLocations = new LinkedHashMap<String, Point>();
|
||||
@@ -55,7 +55,7 @@ public class WorldmapSegment extends GameDataElement {
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return id;
|
||||
return (needsSaving() ? "*" : "")+id;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,7 +69,7 @@ public class WorldmapSegment extends GameDataElement {
|
||||
String area;
|
||||
if ((area = mapNode.getAttribute("area")) != null && !"".equals(area)) {
|
||||
if (labelledMaps.get(area) == null) {
|
||||
labelledMaps.put(area, new LinkedList<String>());
|
||||
labelledMaps.put(area, new ArrayList<String>());
|
||||
}
|
||||
labelledMaps.get(area).add(mapNode.getAttribute("id"));
|
||||
}
|
||||
@@ -90,7 +90,9 @@ public class WorldmapSegment extends GameDataElement {
|
||||
return;
|
||||
}
|
||||
for (String mapName : mapLocations.keySet()) {
|
||||
getProject().getMap(mapName).addBacklink(this);
|
||||
if (getProject().getMap(mapName) != null) {
|
||||
getProject().getMap(mapName).addBacklink(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,8 +105,28 @@ public class WorldmapSegment extends GameDataElement {
|
||||
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
boolean modified = false;
|
||||
if (newOne == null && writable) {
|
||||
//A referenced map may have been deleted.
|
||||
if (mapLocations.containsKey(oldOne.id)) {
|
||||
mapLocations.remove(oldOne.id);
|
||||
modified = true;
|
||||
}
|
||||
for (String label : labelledMaps.keySet()) {
|
||||
if (labelledMaps.get(label).contains(oldOne.id)) {
|
||||
labelledMaps.get(label).remove(oldOne.id);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oldOne.removeBacklink(this);
|
||||
newOne.addBacklink(this);
|
||||
if(newOne != null) newOne.addBacklink(this);
|
||||
|
||||
if (modified) {
|
||||
this.state = GameDataElement.State.modified;
|
||||
childrenChanged(new ArrayList<ProjectTreeNode>());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,6 +177,7 @@ public class WorldmapSegment extends GameDataElement {
|
||||
map.setAttribute("x", Integer.toString(mapLocations.get(s).x + segmentX));
|
||||
map.setAttribute("y", Integer.toString(mapLocations.get(s).y + segmentY));
|
||||
for (String label : labelledMaps.keySet()) {
|
||||
if (TEMP_LABEL_KEY.equals(label)) continue;
|
||||
if (labelledMaps.get(label).contains(s)) {
|
||||
map.setAttribute("area", label);
|
||||
}
|
||||
@@ -162,7 +185,9 @@ public class WorldmapSegment extends GameDataElement {
|
||||
element.appendChild(map);
|
||||
}
|
||||
|
||||
for (NamedArea area : labels.values()) {
|
||||
for (String key : labels.keySet()) {
|
||||
if (TEMP_LABEL_KEY.equals(key)) continue;
|
||||
NamedArea area = labels.get(key);
|
||||
Element namedArea = doc.createElement("namedarea");
|
||||
namedArea.setAttribute("id", area.id);
|
||||
namedArea.setAttribute("name", area.name);
|
||||
|
||||
@@ -97,7 +97,7 @@ public class SavedGame extends GameDataElement {
|
||||
}
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return loadedSave.displayInfo;
|
||||
return (needsSaving() ? "*" : "")+loadedSave.displayInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -128,7 +128,7 @@ public class SavedGamesSet implements ProjectTreeNode, Serializable {
|
||||
}
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return "Saved games";
|
||||
return (needsSaving() ? "*" : "")+"Saved games";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -168,4 +168,13 @@ public class SavedGamesSet implements ProjectTreeNode, Serializable {
|
||||
public boolean isEmpty() {
|
||||
return saves.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
for (ProjectTreeNode node : saves) {
|
||||
if (node.needsSaving()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ public class SpriteSheetSet implements ProjectTreeNode {
|
||||
}
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return "Spritesheets";
|
||||
return (needsSaving() ? "*" : "")+"Spritesheets";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -151,4 +151,12 @@ public class SpriteSheetSet implements ProjectTreeNode {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
for (ProjectTreeNode node : spritesheets) {
|
||||
if (node.needsSaving()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -43,8 +43,8 @@ public class Spritesheet extends GameDataElement {
|
||||
|
||||
//Lazy initialization.
|
||||
public BufferedImage spritesheet = null;
|
||||
public Map<Integer, BufferedImage> cache_full_size = new HashMap<Integer, BufferedImage>();
|
||||
public Map<Integer, Image> cache_icon = new HashMap<Integer, Image>();
|
||||
public Map<Integer, BufferedImage> cache_full_size = new LinkedHashMap<Integer, BufferedImage>();
|
||||
public Map<Integer, Image> cache_icon = new LinkedHashMap<Integer, Image>();
|
||||
|
||||
public Spritesheet(SpriteSheetSet parent, File f) {
|
||||
this.spritesheetFile = f;
|
||||
@@ -118,7 +118,7 @@ public class Spritesheet extends GameDataElement {
|
||||
}
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return spritesheetFile.getName();
|
||||
return (needsSaving() ? "*" : "")+spritesheetFile.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,657 @@
|
||||
package com.gpl.rpg.atcontentstudio.model.tools.writermode;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.Notification;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
|
||||
import com.gpl.rpg.atcontentstudio.model.Project;
|
||||
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
|
||||
import com.gpl.rpg.atcontentstudio.model.SaveEvent;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
|
||||
public class WriterModeData extends GameDataElement {
|
||||
private static final long serialVersionUID = -7062544089063979696L;
|
||||
|
||||
public File jsonFile;
|
||||
|
||||
public Image npcIcon;
|
||||
// public String sketchName;
|
||||
|
||||
|
||||
public List<String> rootsId = new ArrayList<String>();
|
||||
public List<WriterDialogue> roots = new ArrayList<WriterDialogue>();
|
||||
public WriterDialogue begin;
|
||||
public Map<String, WriterDialogue> nodesById = new LinkedHashMap<String, WriterDialogue>();
|
||||
|
||||
//public Map<String, WriterDialogue> dialogueThreads = new LinkedHashMap<String, WriterDialogue>();
|
||||
public Map<String, Integer> threadsNextIndex = new LinkedHashMap<String, Integer>();
|
||||
|
||||
|
||||
public WriterModeData(String id_prefix){
|
||||
this.id = id_prefix;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public WriterModeData(WriterModeDataSet parent, Map jsonObj) {
|
||||
this.parent = parent;
|
||||
this.jsonFile = parent.writerFile;
|
||||
this.parse(jsonObj);
|
||||
this.state = State.parsed;
|
||||
}
|
||||
|
||||
public WriterModeData(String id_prefix, Dialogue imported) {
|
||||
this.id = id_prefix;
|
||||
this.begin = new WriterDialogue(imported);
|
||||
this.state = State.linked;
|
||||
}
|
||||
|
||||
public int getNextIndex(String id_prefix) {
|
||||
Integer index = threadsNextIndex.get(id_prefix);
|
||||
if (index == null) index = 0;
|
||||
while (getProject().getDialogue(id_prefix+index) != null) {
|
||||
index++;
|
||||
}
|
||||
threadsNextIndex.put(id_prefix, index + 1);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
public abstract class WriterNode {
|
||||
public String text;
|
||||
|
||||
public abstract String getTitle();
|
||||
|
||||
}
|
||||
|
||||
public WriterDialogue createDialogue(Dialogue dialogue) {
|
||||
if (dialogue.message == null) {
|
||||
return new SelectorDialogue(dialogue);
|
||||
} else {
|
||||
return new WriterDialogue(dialogue);
|
||||
}
|
||||
}
|
||||
|
||||
public class WriterDialogue extends WriterNode {
|
||||
public String id;
|
||||
public String id_prefix;
|
||||
public int index;
|
||||
public List<WriterReply> replies = new ArrayList<WriterReply>();
|
||||
public List<WriterReply> parents = new ArrayList<WriterReply>();
|
||||
public String dialogue_id;
|
||||
public Dialogue dialogue;
|
||||
|
||||
public WriterDialogue() {}
|
||||
|
||||
public WriterDialogue(Dialogue dialogue) {
|
||||
this.dialogue = dialogue;
|
||||
this.text = dialogue.message;
|
||||
this.id = this.dialogue_id = dialogue.id;
|
||||
Pattern p = Pattern.compile("(.*)([0-9]+)");
|
||||
Matcher m = p.matcher(dialogue.id);
|
||||
if (m.matches()) {
|
||||
this.id_prefix = m.group(1);
|
||||
this.index = Integer.parseInt(m.group(2));
|
||||
} else {
|
||||
this.id_prefix = this.id+"_";
|
||||
}
|
||||
nodesById.put(this.id, this);
|
||||
if (dialogue.replies != null) {
|
||||
for (Dialogue.Reply reply : dialogue.replies) {
|
||||
if (Dialogue.Reply.GO_NEXT_TEXT.equals(reply.text) || reply.text == null) {
|
||||
replies.add(new EmptyReply(this, reply));
|
||||
} else {
|
||||
replies.add(new WriterReply(this, reply));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public WriterDialogue(String id_prefix) {
|
||||
text = "";
|
||||
this.id_prefix = id_prefix;
|
||||
index = getNextIndex(id_prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Dialogue "+getID();
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return this.id != null ? this.id : this.id_prefix+this.index;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void toJson(List<WriterDialogue> visited, List<Map> jsonData) {
|
||||
if (visited.contains(this)) return;
|
||||
visited.add(this);
|
||||
Map dialogueJson = new LinkedHashMap();
|
||||
jsonData.add(dialogueJson);
|
||||
dialogueJson.put("id", id);
|
||||
dialogueJson.put("id_prefix", id_prefix);
|
||||
dialogueJson.put("index", index);
|
||||
dialogueJson.put("text", text);
|
||||
if (dialogue != null) {
|
||||
dialogueJson.put("dialogue", dialogue.id);
|
||||
} else if (dialogue_id != null) {
|
||||
dialogueJson.put("dialogue", dialogue_id);
|
||||
}
|
||||
dialogueJson.put("special", isSpecial());
|
||||
dialogueJson.put("begin", begin == this);
|
||||
if (!replies.isEmpty()) {
|
||||
List repliesJson = new ArrayList();
|
||||
for (WriterReply reply : replies) {
|
||||
repliesJson.add(reply.toJson(visited, jsonData));
|
||||
}
|
||||
dialogueJson.put("replies", repliesJson);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public WriterDialogue(Map json) {
|
||||
this.id = (String) json.get("id");
|
||||
this.index = ((Number)json.get("index")).intValue();
|
||||
this.id_prefix = (String) json.get("id_prefix");
|
||||
if (threadsNextIndex.get(id_prefix) == null || threadsNextIndex.get(id_prefix) <= index) {
|
||||
threadsNextIndex.put(id_prefix, index+1);
|
||||
}
|
||||
this.text = (String) json.get("text");
|
||||
this.dialogue_id = (String) json.get("dialogue");
|
||||
if (json.get("begin") != null && ((Boolean)json.get("begin"))) begin = this;
|
||||
if (json.get("replies") != null) {
|
||||
List repliesJson = (List) json.get("replies");
|
||||
for (Object rJson : repliesJson) {
|
||||
if (((Map)rJson).get("special") != null && (Boolean)((Map)rJson).get("special")) {
|
||||
//TODO Check different cases. But there are none currently.
|
||||
this.replies.add(new EmptyReply(this, ((Map)rJson)));
|
||||
} else {
|
||||
this.replies.add(new WriterReply(this, (Map)rJson));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSpecial() {return false;}
|
||||
|
||||
|
||||
public Dialogue toDialogue(Map<WriterDialogue, Dialogue> visited, List<Dialogue> created, List<Dialogue> modified) {
|
||||
if (visited.get(this) != null) return visited.get(this);
|
||||
//Creating a new Dialogue
|
||||
if (dialogue == null) {
|
||||
dialogue = new Dialogue();
|
||||
dialogue.id = getID();
|
||||
dialogue.state = GameDataElement.State.parsed;
|
||||
created.add(dialogue);
|
||||
} else {
|
||||
if (hasChanged()) {
|
||||
if (dialogue.writable) {
|
||||
//Modifying a created or altered Dialogue
|
||||
dialogue.state = GameDataElement.State.modified;
|
||||
modified.add(dialogue);
|
||||
} else {
|
||||
//Altering a game source Dialogue
|
||||
//Dialogue clone = (Dialogue) dialogue.clone();
|
||||
dialogue.getProject().makeWritable(dialogue);
|
||||
Dialogue clone = dialogue.getProject().getDialogue(dialogue.id);
|
||||
if (this.replies != null) {
|
||||
for (WriterReply wReply : this.replies) {
|
||||
if (wReply.reply != null) {
|
||||
wReply.reply = clone.replies.get(dialogue.replies.indexOf(wReply.reply));
|
||||
}
|
||||
}
|
||||
}
|
||||
dialogue = clone;
|
||||
dialogue.state = GameDataElement.State.parsed;
|
||||
created.add(dialogue);
|
||||
}
|
||||
}
|
||||
}
|
||||
visited.put(this, dialogue);
|
||||
dialogue.message = this.text;
|
||||
if (this.replies != null && !this.replies.isEmpty()) {
|
||||
if (dialogue.replies == null) {
|
||||
dialogue.replies = new ArrayList<Dialogue.Reply>();
|
||||
} else {
|
||||
dialogue.replies.clear();
|
||||
}
|
||||
for (WriterReply wReply : this.replies) {
|
||||
//if (wReply.reply != null && dialogue.replies)
|
||||
dialogue.replies.add(wReply.toReply(visited, created, modified));
|
||||
}
|
||||
} else {
|
||||
dialogue.replies = null;
|
||||
}
|
||||
return dialogue;
|
||||
}
|
||||
|
||||
public boolean hasChanged() {
|
||||
return dialogue == null ||
|
||||
text == null ? dialogue.message!=null : !text.equals(dialogue.message) ||
|
||||
repliesHaveChanged();
|
||||
}
|
||||
|
||||
public boolean repliesHaveChanged() {
|
||||
if (replies.isEmpty() && (dialogue.replies == null || dialogue.replies.isEmpty())) return false;
|
||||
if (!replies.isEmpty() && (dialogue.replies == null || dialogue.replies.isEmpty())) return true;
|
||||
if (replies.isEmpty() && (dialogue.replies != null && !dialogue.replies.isEmpty())) return true;
|
||||
if (replies.size() != dialogue.replies.size()) return true;
|
||||
for (WriterReply reply : replies) {
|
||||
if (reply.hasChanged()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract class SpecialDialogue extends WriterDialogue {
|
||||
|
||||
public SpecialDialogue() {}
|
||||
public boolean isSpecial() {return true;}
|
||||
public abstract SpecialDialogue duplicate();
|
||||
public SpecialDialogue(Dialogue dialogue) {
|
||||
super(dialogue);
|
||||
}
|
||||
}
|
||||
public class SelectorDialogue extends SpecialDialogue {
|
||||
public SelectorDialogue() {}
|
||||
public SpecialDialogue duplicate() {return new SelectorDialogue();}
|
||||
public SelectorDialogue(Dialogue dialogue) {
|
||||
super(dialogue);
|
||||
}
|
||||
}
|
||||
public class ShopDialogue extends SpecialDialogue {
|
||||
public static final String id = Dialogue.Reply.SHOP_PHRASE_ID;
|
||||
public SpecialDialogue duplicate() {return new ShopDialogue();}
|
||||
}
|
||||
public class FightDialogue extends SpecialDialogue {
|
||||
public static final String id = Dialogue.Reply.FIGHT_PHRASE_ID;
|
||||
public SpecialDialogue duplicate() {return new FightDialogue();}
|
||||
}
|
||||
public class EndDialogue extends SpecialDialogue {
|
||||
public static final String id = Dialogue.Reply.EXIT_PHRASE_ID;
|
||||
public SpecialDialogue duplicate() {return new EndDialogue();}
|
||||
}
|
||||
public class RemoveNPCDialogue extends SpecialDialogue {
|
||||
public static final String id = Dialogue.Reply.REMOVE_PHRASE_ID;
|
||||
public SpecialDialogue duplicate() {return new RemoveNPCDialogue();}
|
||||
}
|
||||
|
||||
public class WriterReply extends WriterNode {
|
||||
public WriterDialogue parent;
|
||||
public String next_dialogue_id;
|
||||
public WriterDialogue next_dialogue;
|
||||
public Dialogue.Reply reply;
|
||||
|
||||
public WriterReply() {}
|
||||
|
||||
public WriterReply(WriterDialogue parent) {
|
||||
this.parent = parent;
|
||||
this.text = "";
|
||||
parent.replies.add(this);
|
||||
}
|
||||
|
||||
public WriterReply(WriterDialogue parent, Dialogue.Reply reply) {
|
||||
this.parent = parent;
|
||||
this.reply = reply;
|
||||
this.text = reply.text;
|
||||
this.next_dialogue_id = reply.next_phrase_id;
|
||||
if (nodesById.get(this.next_dialogue_id) != null) {
|
||||
this.next_dialogue = nodesById.get(this.next_dialogue_id);
|
||||
} else if (reply.next_phrase != null ){
|
||||
this.next_dialogue = new WriterDialogue(reply.next_phrase);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public WriterReply(WriterDialogue parent, Map json) {
|
||||
this.parent = parent;
|
||||
this.text = (String) json.get("text");
|
||||
if (json.containsKey("next_dialogue_id")) {
|
||||
next_dialogue_id = (String) json.get("next_dialogue_id");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Reply in "+parent.id_prefix+parent.index;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public Map toJson(List<WriterDialogue> visited, List<Map> jsonData) {
|
||||
Map replyJson = new LinkedHashMap();
|
||||
replyJson.put("text", text);
|
||||
replyJson.put("special", isSpecial());
|
||||
if (next_dialogue != null) {
|
||||
replyJson.put("next_dialogue_id", next_dialogue.getID());
|
||||
next_dialogue.toJson(visited, jsonData);
|
||||
}
|
||||
return replyJson;
|
||||
}
|
||||
|
||||
public boolean isSpecial() {return false;}
|
||||
|
||||
public Dialogue.Reply toReply(Map<WriterDialogue, Dialogue> visited, List<Dialogue> created, List<Dialogue> modified) {
|
||||
if (reply == null) {
|
||||
reply = new Dialogue.Reply();
|
||||
}
|
||||
reply.text = this.text;
|
||||
if (this.next_dialogue != null) {
|
||||
this.next_dialogue.toDialogue(visited, created, modified);
|
||||
reply.next_phrase_id = this.next_dialogue.getID();
|
||||
} else if (this.next_dialogue_id != null) {
|
||||
reply.next_phrase_id = this.next_dialogue_id;
|
||||
} else {
|
||||
reply.next_phrase_id = Dialogue.Reply.EXIT_PHRASE_ID;
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
|
||||
public boolean hasChanged() {
|
||||
if (reply == null) return true;
|
||||
if (text == null && reply.text != null) return true;
|
||||
if (text != null && reply.text == null) return true;
|
||||
if (text != null && !text.equals(reply.text)) return true;
|
||||
String targetDialogueId = next_dialogue != null ? next_dialogue.getID() : next_dialogue_id;
|
||||
String replyTargetDialogueId = reply.next_phrase != null ? reply.next_phrase.id : reply.next_phrase_id;
|
||||
if (targetDialogueId == null && replyTargetDialogueId != null) return true;
|
||||
if (targetDialogueId != null && replyTargetDialogueId == null) return true;
|
||||
if (targetDialogueId != null && !targetDialogueId.equals(replyTargetDialogueId)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class SpecialReply extends WriterReply {
|
||||
|
||||
public boolean isSpecial() {return true;}
|
||||
|
||||
public SpecialReply(WriterDialogue parent, Dialogue.Reply reply) {
|
||||
super(parent, reply);
|
||||
}
|
||||
|
||||
public SpecialReply(WriterDialogue parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
public SpecialReply(WriterDialogue parent, @SuppressWarnings("rawtypes") Map json) {
|
||||
super(parent, json);
|
||||
}
|
||||
}
|
||||
public class EmptyReply extends SpecialReply {
|
||||
|
||||
public EmptyReply(WriterDialogue parent, Dialogue.Reply reply) {
|
||||
super(parent, reply);
|
||||
text = Dialogue.Reply.GO_NEXT_TEXT;
|
||||
}
|
||||
|
||||
public EmptyReply(WriterDialogue parent) {
|
||||
super(parent);
|
||||
text = Dialogue.Reply.GO_NEXT_TEXT;
|
||||
}
|
||||
|
||||
public EmptyReply(WriterDialogue parent, @SuppressWarnings("rawtypes") Map json) {
|
||||
super(parent, json);
|
||||
text = Dialogue.Reply.GO_NEXT_TEXT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return (needsSaving() ? "*" : "")+id;
|
||||
}
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return parent.getProject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getIcon() {
|
||||
return DefaultIcons.getDialogueIcon();
|
||||
}
|
||||
@Override
|
||||
public Image getOpenIcon() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Image getClosedIcon() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Image getLeafIcon() {
|
||||
return getIcon();
|
||||
}
|
||||
@Override
|
||||
public GameDataSet getDataSet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameDataElement clone() {
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
// Useless here.
|
||||
|
||||
}
|
||||
@Override
|
||||
public String getProjectFilename() {
|
||||
return WriterModeDataSet.DEFAULT_REL_PATH_IN_PROJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
((WriterModeDataSet)this.getParent()).save(this.jsonFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SaveEvent> attemptSave() {
|
||||
List<SaveEvent> events = ((WriterModeDataSet)parent).attemptSave();
|
||||
if (events == null || events.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (events.size() == 1 && events.get(0).type == SaveEvent.Type.alsoSave && events.get(0).target == this) {
|
||||
save();
|
||||
return null;
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public Map toJson() {
|
||||
List<Map> jsonData = new ArrayList<Map>();
|
||||
begin.toJson(new ArrayList<WriterModeData.WriterDialogue>(), jsonData);
|
||||
Map jsonObj = new LinkedHashMap();
|
||||
jsonObj.put("id", id);
|
||||
jsonObj.put("dialogues", jsonData);
|
||||
return jsonObj;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void parse() {
|
||||
if (this.state == State.created || this.state == State.modified || this.state == State.saved) {
|
||||
//This type of state is unrelated to parsing/linking.
|
||||
return;
|
||||
}
|
||||
JSONParser parser = new JSONParser();
|
||||
FileReader reader = null;
|
||||
try {
|
||||
reader = new FileReader(jsonFile);
|
||||
List gameDataElements = (List) parser.parse(reader);
|
||||
for (Object obj : gameDataElements) {
|
||||
Map jsonObj = (Map)obj;
|
||||
String id = (String) jsonObj.get("id");
|
||||
if (id != null && id.equals(this.id )) {
|
||||
this.parse(jsonObj);
|
||||
this.state = State.parsed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Notification.addError("Error while parsing JSON file "+jsonFile.getAbsolutePath()+": "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
Notification.addError("Error while parsing JSON file "+jsonFile.getAbsolutePath()+": "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (ParseException e) {
|
||||
Notification.addError("Error while parsing JSON file "+jsonFile.getAbsolutePath()+": "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (reader != null)
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void parse(Map json) {
|
||||
this.id = (String) json.get("id");
|
||||
// this.sketchName = (String) json.get("name");
|
||||
// List jsonRootsId = (List) json.get("roots_id");
|
||||
// if (jsonRootsId != null) {
|
||||
// for (Object jsonRootId : jsonRootsId) {
|
||||
// rootsId.add((String) jsonRootId);
|
||||
// }
|
||||
// }
|
||||
List jsonDialogues = (List) json.get("dialogues");
|
||||
if (jsonDialogues != null) {
|
||||
for (Object jsonDialogue : jsonDialogues) {
|
||||
WriterDialogue dialogue = new WriterDialogue((Map)jsonDialogue);
|
||||
nodesById.put(dialogue.getID(), dialogue);
|
||||
}
|
||||
}
|
||||
|
||||
this.state = State.parsed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void link() {
|
||||
if (this.state == State.created) {
|
||||
this.begin = new WriterDialogue();
|
||||
begin.id_prefix = id;
|
||||
begin.index = getNextIndex(id);
|
||||
begin.text = "";
|
||||
}
|
||||
if (this.state == State.init) {
|
||||
//Not parsed yet.
|
||||
this.parse();
|
||||
}
|
||||
if (this.state == State.parsed) {
|
||||
for (String prefix : threadsNextIndex.keySet()) {
|
||||
while (getProject().getDialogue(prefix+threadsNextIndex.get(prefix)) != null) {
|
||||
threadsNextIndex.put(prefix, threadsNextIndex.get(prefix)+1);
|
||||
}
|
||||
}
|
||||
for (WriterDialogue dialogue : nodesById.values()) {
|
||||
if (dialogue.dialogue_id != null) {
|
||||
dialogue.dialogue = getProject().getDialogue(dialogue.dialogue_id);
|
||||
}
|
||||
if (dialogue.replies == null) continue;
|
||||
for (WriterReply reply : dialogue.replies) {
|
||||
if (reply.next_dialogue_id != null) {
|
||||
if (isSpecial(reply.next_dialogue_id)) {
|
||||
reply.next_dialogue = getSpecial(reply.next_dialogue_id);
|
||||
} else {
|
||||
reply.next_dialogue = nodesById.get(reply.next_dialogue_id);
|
||||
}
|
||||
}
|
||||
//TODO Seriously, this is failure-prone by design. Can't do much better though...
|
||||
if (dialogue.dialogue != null) {
|
||||
List<Dialogue.Reply> linked = new ArrayList<Dialogue.Reply>(dialogue.dialogue.replies.size());
|
||||
if (dialogue.dialogue != null && dialogue.dialogue.replies != null) {
|
||||
//Try to hook to existing replies... not as easy when there's no ID.
|
||||
Dialogue.Reply best = null;
|
||||
int score, maxScore = 0;
|
||||
for (Dialogue.Reply dReply : dialogue.dialogue.replies) {
|
||||
//Never link twice to the same...
|
||||
if (linked.contains(dReply)) continue;
|
||||
score = 0;
|
||||
//Arbitrary values... hopefully this gives good results.
|
||||
//Same target gives good hope of preserving at least the structure.
|
||||
if (dReply.next_phrase_id != null && dReply.next_phrase_id.equals(reply.next_dialogue_id)) score +=50;
|
||||
//Same text is almost as good as an ID, but there may be duplicates due to requirements system...
|
||||
if (dReply.text != null && dReply.text.equals(reply.text)) score +=40;
|
||||
//Same slot in the list. That's not so bad if all else fails, and could help sort duplicates with same text.
|
||||
if (dialogue.dialogue.replies.indexOf(dReply) == dialogue.replies.indexOf(reply)) score +=20;
|
||||
//Both have null text. It's not much, but it's something....
|
||||
if (dReply.text == null && reply.text == null) score += 10;
|
||||
if (score > maxScore) {
|
||||
maxScore = score;
|
||||
best = dReply;
|
||||
}
|
||||
}
|
||||
if (maxScore > 0) {
|
||||
reply.reply = best;
|
||||
linked.add(best);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String rootId : rootsId) {
|
||||
roots.add(nodesById.get(rootId));
|
||||
}
|
||||
|
||||
}
|
||||
if (this.state == State.linked) {
|
||||
//Already linked.
|
||||
return;
|
||||
}
|
||||
|
||||
this.state = State.linked;
|
||||
}
|
||||
|
||||
public boolean isSpecial(String id) {
|
||||
if (id == null) return false;
|
||||
if (ShopDialogue.id.equals(id)) return true;
|
||||
if (FightDialogue.id.equals(id)) return true;
|
||||
if (EndDialogue.id.equals(id)) return true;
|
||||
if (RemoveNPCDialogue.id.equals(id)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public SpecialDialogue getSpecial(String id) {
|
||||
if (id == null) return null;
|
||||
if (ShopDialogue.id.equals(id)) return new ShopDialogue();
|
||||
if (FightDialogue.id.equals(id)) return new FightDialogue();
|
||||
if (EndDialogue.id.equals(id)) return new EndDialogue();
|
||||
if (RemoveNPCDialogue.id.equals(id)) return new RemoveNPCDialogue();
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Dialogue> toDialogue(){
|
||||
Map<WriterModeData.WriterDialogue, Dialogue> visited = new LinkedHashMap<WriterModeData.WriterDialogue, Dialogue>();
|
||||
List<Dialogue> created = new ArrayList<Dialogue>();
|
||||
List<Dialogue> modified = new ArrayList<Dialogue>();
|
||||
begin.toDialogue(visited, created, modified);
|
||||
for (Dialogue modifiedDialogue : modified) {
|
||||
modifiedDialogue.childrenChanged(new ArrayList<ProjectTreeNode>());
|
||||
}
|
||||
return created;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
package com.gpl.rpg.atcontentstudio.model.tools.writermode;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.Notification;
|
||||
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.GameSource.Type;
|
||||
import com.gpl.rpg.atcontentstudio.model.Project;
|
||||
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;
|
||||
|
||||
public class WriterModeDataSet implements ProjectTreeNode, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5434504851883441971L;
|
||||
public static final String DEFAULT_REL_PATH_IN_PROJECT = "writer.json";
|
||||
|
||||
|
||||
public GameSource parent;
|
||||
public File writerFile;
|
||||
|
||||
public List<WriterModeData> writerModeDataList = new ArrayList<WriterModeData>();
|
||||
|
||||
public WriterModeDataSet(GameSource gameSource) {
|
||||
this.parent = gameSource;
|
||||
writerFile = new File(parent.baseFolder, DEFAULT_REL_PATH_IN_PROJECT);
|
||||
parse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeNode getChildAt(int childIndex) {
|
||||
return writerModeDataList.get(childIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount() {
|
||||
return writerModeDataList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex(TreeNode node) {
|
||||
return writerModeDataList.indexOf(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAllowsChildren() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeaf() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Enumeration children() {
|
||||
return Collections.enumeration(writerModeDataList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenAdded(List<ProjectTreeNode> path) {
|
||||
path.add(0,this);
|
||||
parent.childrenAdded(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenChanged(List<ProjectTreeNode> path) {
|
||||
path.add(0,this);
|
||||
parent.childrenChanged(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenRemoved(List<ProjectTreeNode> path) {
|
||||
path.add(0,this);
|
||||
parent.childrenRemoved(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyCreated() {
|
||||
childrenAdded(new ArrayList<ProjectTreeNode>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return (needsSaving() ? "*" : "")+"Dialogue sketches";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return parent.getProject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameDataSet getDataSet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getIcon() {
|
||||
return DefaultIcons.getStdClosedIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getOpenIcon() {
|
||||
return DefaultIcons.getStdOpenIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getClosedIcon() {
|
||||
return DefaultIcons.getStdClosedIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getLeafIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getDataType() {
|
||||
return parent.getDataType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return writerModeDataList.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void save(File jsonFile) {
|
||||
List<Map> dataToSave = new ArrayList<Map>();
|
||||
for (WriterModeData data : writerModeDataList) {
|
||||
if (data.jsonFile.equals(jsonFile)) {
|
||||
dataToSave.add(data.toJson());
|
||||
}
|
||||
}
|
||||
if (dataToSave.isEmpty() && writerFile.exists()) {
|
||||
if (writerFile.delete()) {
|
||||
Notification.addSuccess("File "+writerFile.getAbsolutePath()+" deleted.");
|
||||
} else {
|
||||
Notification.addError("Error deleting file "+writerFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
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(writerFile);
|
||||
w.write(toWrite);
|
||||
w.close();
|
||||
for (WriterModeData element : writerModeDataList) {
|
||||
element.state = GameDataElement.State.saved;
|
||||
}
|
||||
Notification.addSuccess("Json file "+writerFile.getAbsolutePath()+" saved.");
|
||||
} catch (IOException e) {
|
||||
Notification.addError("Error while writing json file "+writerFile.getAbsolutePath()+" : "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public List<SaveEvent> attemptSave() {
|
||||
List<SaveEvent> events = new ArrayList<SaveEvent>();
|
||||
for (WriterModeData data : writerModeDataList) {
|
||||
if (data.needsSaving()) {
|
||||
events.add(new SaveEvent(SaveEvent.Type.alsoSave, data));
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void parse() {
|
||||
if (!writerFile.exists()) return;
|
||||
JSONParser parser = new JSONParser();
|
||||
FileReader reader = null;
|
||||
try {
|
||||
reader = new FileReader(writerFile);
|
||||
List writerDataListJson = (List) parser.parse(reader);
|
||||
for (Object obj : writerDataListJson) {
|
||||
Map jsonObj = (Map)obj;
|
||||
WriterModeData data = new WriterModeData(this, jsonObj);
|
||||
data.writable = true;
|
||||
writerModeDataList.add(data);
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Notification.addError("Error while parsing JSON file "+writerFile.getAbsolutePath()+": "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
Notification.addError("Error while parsing JSON file "+writerFile.getAbsolutePath()+": "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (ParseException e) {
|
||||
Notification.addError("Error while parsing JSON file "+writerFile.getAbsolutePath()+": "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (reader != null)
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public WriterModeData getWriterSketch(String id) {
|
||||
for (WriterModeData sketch : writerModeDataList) {
|
||||
if (id.equals(sketch.id)){
|
||||
return sketch;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public WriterModeData get(int index) {
|
||||
return writerModeDataList.get(index);
|
||||
}
|
||||
|
||||
public void add(WriterModeData node) {
|
||||
ProjectTreeNode higherEmptyParent = this;
|
||||
while (higherEmptyParent != null) {
|
||||
if (higherEmptyParent.getParent() != null && ((ProjectTreeNode)higherEmptyParent.getParent()).isEmpty()) higherEmptyParent = (ProjectTreeNode)higherEmptyParent.getParent();
|
||||
else break;
|
||||
}
|
||||
if (higherEmptyParent == this && !this.isEmpty()) higherEmptyParent = null;
|
||||
writerModeDataList.add(node);
|
||||
node.writable = true;
|
||||
if (node.jsonFile == null) node.jsonFile = this.writerFile;
|
||||
node.parent = this;
|
||||
if (higherEmptyParent != null) higherEmptyParent.notifyCreated();
|
||||
else node.notifyCreated();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean needsSaving() {
|
||||
for (ProjectTreeNode node : writerModeDataList) {
|
||||
if (node.needsSaving()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class AboutEditor extends Editor {
|
||||
"<br/>" +
|
||||
"Play <a href=\"https://play.google.com/store/apps/details?id=com.gpl.rpg.AndorsTrail\">Andor's Trail</a> for free on your Android device.<br/>" +
|
||||
"Visit <a href=\"http://andorstrail.com/\">the official forum</a> to give or receive help.<br/>" +
|
||||
"Open the project's <a href=\"https://code.google.com/p/andors-trail/\">Google Code page</a> to check out the game's source code.<br/>" +
|
||||
"Open the project's <a href=\"https://github.com/Zukero/andors-trail/\">GitHub project page</a> to check out the game's source code.<br/>" +
|
||||
"<br/>" +
|
||||
"For content creation help, make sure to use the following resources:<br/>" +
|
||||
"<a href=\"http://andorstrail.com/viewtopic.php?f=6&t=4560\">The contribution guide on the forums</a><br/>" +
|
||||
@@ -72,6 +72,12 @@ public class AboutEditor extends Editor {
|
||||
"<a href=\"http://www.beanshell.org/\">BeanShell</a> by Pat Niemeyer.<br/>" +
|
||||
"License: <a href=\"http://www.beanshell.org/license.html\">LGPL v3</a><br/>" +
|
||||
"<br/>" +
|
||||
"A slightly modified version of <a href=\"https://github.com/zackehh/siphash-java\">SipHash for Java</a> by Isaac Whitfield.<br/>" +
|
||||
"License: <a href=\"https://github.com/zackehh/siphash-java/blob/master/LICENSE\">MIT License</a><br/>" +
|
||||
"<br/>" +
|
||||
"<a href=\"https://jsoup.org/\">jsoup</a> by Jonathan Hedley<br/>" +
|
||||
"License: <a href=\"https://jsoup.org/license\">MIT License</a><br/>" +
|
||||
"<br/>" +
|
||||
"See the tabs below to find the full license text for each of these.<br/>" +
|
||||
"<br/>" +
|
||||
"The Windows installer was created with:<br/>" +
|
||||
@@ -81,6 +87,7 @@ public class AboutEditor extends Editor {
|
||||
|
||||
|
||||
public static final AboutEditor instance = new AboutEditor();
|
||||
@SuppressWarnings("resource")
|
||||
private AboutEditor() {
|
||||
this.name="About "+ATContentStudio.APP_NAME;
|
||||
this.icon = new ImageIcon(DefaultIcons.getMainIconIcon());
|
||||
@@ -120,6 +127,8 @@ public class AboutEditor extends Editor {
|
||||
editorTabsHolder.add("libtiled-java License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.libtiled.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
|
||||
editorTabsHolder.add("prefuse License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/license-prefuse.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
|
||||
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("ATCS License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.GPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.gpl.rpg.atcontentstudio.ui;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
@@ -11,8 +11,8 @@ import com.gpl.rpg.atcontentstudio.Notification;
|
||||
|
||||
public class DefaultIcons {
|
||||
|
||||
private static Map<String, Image> imageCache = new HashMap<String, Image>();
|
||||
private static Map<String, Image> iconCache = new HashMap<String, Image>();
|
||||
private static Map<String, Image> imageCache = new LinkedHashMap<String, Image>();
|
||||
private static Map<String, Image> iconCache = new LinkedHashMap<String, Image>();
|
||||
|
||||
|
||||
private static String MAIN_ICON_RES = "/com/gpl/rpg/atcontentstudio/img/andorstrainer.png";
|
||||
@@ -227,10 +227,35 @@ public class DefaultIcons {
|
||||
public static Image getCreateTileLayerImage() { return getImage(CREATE_TILE_LAYER_RES); }
|
||||
public static Image getCreateTileLayerIcon() { return getIcon(CREATE_TILE_LAYER_RES); }
|
||||
|
||||
private static String LABEL_RES = "/com/gpl/rpg/atcontentstudio/img/label.png";
|
||||
public static Image getLabelImage() { return getImage(LABEL_RES); }
|
||||
public static Image getLabelIcon() { return getIcon(LABEL_RES); }
|
||||
|
||||
private static String ZOOM_RES = "/com/gpl/rpg/atcontentstudio/img/zoom.png";
|
||||
public static Image getZoomImage() { return getImage(ZOOM_RES); }
|
||||
public static Image getZoomIcon() { return getIcon(ZOOM_RES); }
|
||||
|
||||
private static String STATUS_RED_RES = "/com/gpl/rpg/atcontentstudio/img/status_red.png";
|
||||
public static Image getStatusRedImage() { return getImage(STATUS_RED_RES); }
|
||||
public static Image getStatusRedIcon() { return getIcon(STATUS_RED_RES); }
|
||||
|
||||
private static String STATUS_ORANGE_RES = "/com/gpl/rpg/atcontentstudio/img/status_orange.png";
|
||||
public static Image getStatusOrangeImage() { return getImage(STATUS_ORANGE_RES); }
|
||||
public static Image getStatusOrangeIcon() { return getIcon(STATUS_ORANGE_RES); }
|
||||
|
||||
private static String STATUS_GREEN_RES = "/com/gpl/rpg/atcontentstudio/img/status_green.png";
|
||||
public static Image getStatusGreenImage() { return getImage(STATUS_GREEN_RES); }
|
||||
public static Image getStatusGreenIcon() { return getIcon(STATUS_GREEN_RES); }
|
||||
|
||||
private static String STATUS_BLUE_RES = "/com/gpl/rpg/atcontentstudio/img/status_blue.png";
|
||||
public static Image getStatusBlueImage() { return getImage(STATUS_BLUE_RES); }
|
||||
public static Image getStatusBlueIcon() { return getIcon(STATUS_BLUE_RES); }
|
||||
|
||||
private static String STATUS_UNKNOWN_RES = "/com/gpl/rpg/atcontentstudio/img/status_unknown.png";
|
||||
public static Image getStatusUnknownImage() { return getImage(STATUS_UNKNOWN_RES); }
|
||||
public static Image getStatusUnknownIcon() { return getIcon(STATUS_UNKNOWN_RES); }
|
||||
|
||||
|
||||
private static Image getImage(String res) {
|
||||
if (imageCache.get(res) == null) {
|
||||
try {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.gpl.rpg.atcontentstudio.ui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
@@ -10,10 +12,15 @@ import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import javax.swing.AbstractListModel;
|
||||
import javax.swing.ComboBoxModel;
|
||||
@@ -29,8 +36,10 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSpinner;
|
||||
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;
|
||||
@@ -39,12 +48,14 @@ import javax.swing.event.DocumentListener;
|
||||
import javax.swing.event.ListDataEvent;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import javax.swing.text.DefaultFormatter;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.ATContentStudio;
|
||||
import com.gpl.rpg.atcontentstudio.Notification;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
|
||||
import com.gpl.rpg.atcontentstudio.model.Project;
|
||||
import com.gpl.rpg.atcontentstudio.model.ProjectElementListener;
|
||||
import com.gpl.rpg.atcontentstudio.model.Workspace;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist;
|
||||
@@ -53,7 +64,9 @@ 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.TMXMap;
|
||||
import com.gpl.rpg.atcontentstudio.utils.WeblateIntegration;
|
||||
import com.jidesoft.swing.ComboBoxSearchable;
|
||||
import com.jidesoft.swing.JideBoxLayout;
|
||||
|
||||
@@ -105,6 +118,101 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
return addTextField(pane, label, value, false, nullListener);
|
||||
}
|
||||
|
||||
public static void addTranslationPane(JPanel pane, final JTextComponent tfComponent, final String initialValue) {if (Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue() != null) {
|
||||
JPanel labelPane = new JPanel();
|
||||
labelPane.setLayout(new JideBoxLayout(labelPane, JideBoxLayout.LINE_AXIS, 6));
|
||||
final JLabel translateLinkLabel = new JLabel(getWeblateLabelLink(initialValue));
|
||||
labelPane.add(translateLinkLabel, JideBoxLayout.FIX);
|
||||
labelPane.add(new JLabel(" "), JideBoxLayout.FIX);
|
||||
final JLabel translationStatus = new JLabel("Retrieving...");
|
||||
translationStatus.setIcon(new ImageIcon(DefaultIcons.getStatusUnknownIcon()));
|
||||
translationStatus.setToolTipText("Connecting to weblate...");
|
||||
labelPane.add(translationStatus, JideBoxLayout.VARY);
|
||||
new Thread() {
|
||||
public void run() {
|
||||
WeblateIntegration.WeblateTranslationUnit unit = WeblateIntegration.getTranslationUnit(initialValue);
|
||||
switch (unit.status) {
|
||||
case absent:
|
||||
translationStatus.setIcon(new ImageIcon(DefaultIcons.getStatusRedIcon()));
|
||||
translationStatus.setToolTipText("This string isn't managed by weblate (yet).");
|
||||
break;
|
||||
case done:
|
||||
translationStatus.setIcon(new ImageIcon(DefaultIcons.getStatusGreenIcon()));
|
||||
translationStatus.setToolTipText("This string is translated on weblate.");
|
||||
break;
|
||||
case fuzzy:
|
||||
translationStatus.setIcon(new ImageIcon(DefaultIcons.getStatusOrangeIcon()));
|
||||
translationStatus.setToolTipText("This string is translated on weblate, but needs a review.");
|
||||
break;
|
||||
case notTranslated:
|
||||
translationStatus.setIcon(new ImageIcon(DefaultIcons.getStatusRedIcon()));
|
||||
translationStatus.setToolTipText("This string isn't translated in your language on weblate yet.");
|
||||
break;
|
||||
case warning:
|
||||
translationStatus.setIcon(new ImageIcon(DefaultIcons.getStatusOrangeIcon()));
|
||||
translationStatus.setToolTipText("This string is translated on weblate, but triggered some weblate checks.");
|
||||
break;
|
||||
case error:
|
||||
translationStatus.setIcon(new ImageIcon(DefaultIcons.getStatusRedIcon()));
|
||||
translationStatus.setToolTipText("Cannot connect to weblate. Check internet connection and firewall settings.");
|
||||
break;
|
||||
case notAllowed:
|
||||
translationStatus.setIcon(new ImageIcon(DefaultIcons.getStatusBlueIcon()));
|
||||
translationStatus.setToolTipText("You have not allowed ATCS to access to internet. You can change this in the workspace settings.");
|
||||
break;
|
||||
}
|
||||
translationStatus.setText(unit.translatedText);
|
||||
};
|
||||
}.start();
|
||||
pane.add(labelPane, JideBoxLayout.FIX);
|
||||
tfComponent.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
translateLinkLabel.setText(getWeblateLabelLink(tfComponent.getText().replaceAll("\n", Matcher.quoteReplacement("\n"))));
|
||||
translateLinkLabel.revalidate();
|
||||
translateLinkLabel.repaint();
|
||||
}
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
translateLinkLabel.setText(getWeblateLabelLink(tfComponent.getText().replaceAll("\n", Matcher.quoteReplacement("\n"))));
|
||||
translateLinkLabel.revalidate();
|
||||
translateLinkLabel.repaint();
|
||||
}
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
translateLinkLabel.setText(getWeblateLabelLink(tfComponent.getText().replaceAll("\n", Matcher.quoteReplacement("\n"))));
|
||||
translateLinkLabel.revalidate();
|
||||
translateLinkLabel.repaint();
|
||||
}
|
||||
});
|
||||
translateLinkLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||
translateLinkLabel.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getButton() == MouseEvent.BUTTON1) {
|
||||
try {
|
||||
Desktop.getDesktop().browse(new URI(WeblateIntegration.getWeblateLabelURI(tfComponent.getText().replaceAll("\n", Matcher.quoteReplacement("\n")))));
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (URISyntaxException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static JTextField addTranslatableTextField(JPanel pane, String label, String initialValue, boolean editable, final FieldUpdateListener listener) {
|
||||
final JTextField tfField = addTextField(pane, label, initialValue, editable, listener);
|
||||
addTranslationPane(pane, tfField, initialValue);
|
||||
return tfField;
|
||||
}
|
||||
|
||||
public static String getWeblateLabelLink(String text) {
|
||||
return "<html><a href=\""+WeblateIntegration.getWeblateLabelURI(text)+"\">Translate on weblate</a></html>";
|
||||
}
|
||||
|
||||
public static JTextField addTextField(JPanel pane, String label, String initialValue, boolean editable, final FieldUpdateListener listener) {
|
||||
JPanel tfPane = new JPanel();
|
||||
tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6));
|
||||
@@ -147,17 +255,76 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
});
|
||||
return tfField;
|
||||
}
|
||||
|
||||
|
||||
public static JTextArea addTranslatableTextArea(JPanel pane, String label, String initialValue, boolean editable, final FieldUpdateListener listener) {
|
||||
final JTextArea tfArea = addTextArea(pane, label, initialValue, editable, listener);
|
||||
addTranslationPane(pane, tfArea, initialValue);
|
||||
return tfArea;
|
||||
}
|
||||
|
||||
public static JTextArea addTextArea(JPanel pane, String label, String initialValue, boolean editable, final FieldUpdateListener listener) {
|
||||
String text= initialValue == null ? "" : initialValue.replaceAll("\\n", "\n");
|
||||
|
||||
JPanel tfPane = new JPanel();
|
||||
tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6));
|
||||
JLabel tfLabel = new JLabel(label);
|
||||
tfPane.add(tfLabel, JideBoxLayout.FIX);
|
||||
final JTextArea tfArea = new JTextArea(text);
|
||||
tfArea.setEditable(editable);
|
||||
tfArea.setRows(2);
|
||||
tfArea.setLineWrap(true);
|
||||
tfArea.setWrapStyleWord(true);
|
||||
tfPane.add(new JScrollPane(tfArea), JideBoxLayout.VARY);
|
||||
JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
|
||||
tfPane.add(nullify, JideBoxLayout.FIX);
|
||||
nullify.setEnabled(editable);
|
||||
pane.add(tfPane, JideBoxLayout.FIX);
|
||||
|
||||
nullify.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
tfArea.setText("");
|
||||
listener.valueChanged(tfArea, null);
|
||||
}
|
||||
});
|
||||
tfArea.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
listener.valueChanged(tfArea, tfArea.getText().replaceAll("\n", Matcher.quoteReplacement("\n")));
|
||||
}
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
listener.valueChanged(tfArea, tfArea.getText().replaceAll("\n", Matcher.quoteReplacement("\n")));
|
||||
}
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
listener.valueChanged(tfArea, tfArea.getText().replaceAll("\n", Matcher.quoteReplacement("\n")));
|
||||
}
|
||||
});
|
||||
// tfArea.addActionListener(new ActionListener() {
|
||||
// @Override
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// listener.valueChanged(tfArea, tfArea.getText().replaceAll("\n", "\\n"));
|
||||
// }
|
||||
// });
|
||||
return tfArea;
|
||||
}
|
||||
|
||||
// public static JSpinner addIntegerField(JPanel pane, String label, Integer initialValue, boolean allowNegatives, boolean editable) {
|
||||
// return addIntegerField(pane, label, initialValue, allowNegatives, editable, nullListener);
|
||||
// }
|
||||
|
||||
public static JSpinner addIntegerField(JPanel pane, String label, Integer initialValue, boolean allowNegatives, boolean editable, final FieldUpdateListener listener) {
|
||||
return addIntegerField(pane, label, initialValue, 0, allowNegatives, editable, listener);
|
||||
}
|
||||
|
||||
public static JSpinner addIntegerField(JPanel pane, String label, Integer initialValue, Integer defaultValue, boolean allowNegatives, boolean editable, final FieldUpdateListener listener) {
|
||||
JPanel tfPane = new JPanel();
|
||||
tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6));
|
||||
JLabel tfLabel = new JLabel(label);
|
||||
tfPane.add(tfLabel, JideBoxLayout.FIX);
|
||||
final JSpinner spinner = new JSpinner(new SpinnerNumberModel(initialValue != null ? initialValue.intValue() : 0, allowNegatives ? Integer.MIN_VALUE : 0, Integer.MAX_VALUE, 1));
|
||||
final JSpinner spinner = new JSpinner(new SpinnerNumberModel(initialValue != null ? initialValue.intValue() : defaultValue.intValue(), allowNegatives ? Integer.MIN_VALUE : 0, Integer.MAX_VALUE, 1));
|
||||
((JSpinner.DefaultEditor)spinner.getEditor()).getTextField().setHorizontalAlignment(JTextField.LEFT);
|
||||
spinner.setEnabled(editable);
|
||||
((DefaultFormatter)((NumberEditor)spinner.getEditor()).getTextField().getFormatter()).setCommitsOnValidEdit(true);
|
||||
@@ -259,15 +426,18 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
return bbcb;
|
||||
}
|
||||
|
||||
public static JComboBox addEnumValueBox(JPanel pane, String label, @SuppressWarnings("rawtypes") Enum[] values, @SuppressWarnings("rawtypes") Enum initialValue, boolean writable) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static JComboBox addEnumValueBox(JPanel pane, String label, Enum[] values, Enum initialValue, boolean writable) {
|
||||
return addEnumValueBox(pane, label, values, initialValue, writable, new FieldUpdateListener() {@Override public void valueChanged(JComponent source, Object value) {}});
|
||||
}
|
||||
|
||||
public static JComboBox addEnumValueBox(JPanel pane, String label, @SuppressWarnings("rawtypes") Enum[] values, @SuppressWarnings("rawtypes") Enum initialValue, boolean writable, final FieldUpdateListener listener) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static JComboBox addEnumValueBox(JPanel pane, String label, Enum[] values, Enum initialValue, boolean writable, final FieldUpdateListener listener) {
|
||||
JPanel comboPane = new JPanel();
|
||||
comboPane.setLayout(new JideBoxLayout(comboPane, JideBoxLayout.LINE_AXIS, 6));
|
||||
JLabel comboLabel = new JLabel(label);
|
||||
comboPane.add(comboLabel, JideBoxLayout.FIX);
|
||||
@SuppressWarnings("unchecked")
|
||||
final JComboBox enumValuesCombo = new JComboBox(values);
|
||||
enumValuesCombo.setEnabled(writable);
|
||||
enumValuesCombo.setSelectedItem(initialValue);
|
||||
@@ -300,7 +470,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
final GDEComboModel<NPC> comboModel = new GDEComboModel<NPC>(proj, npc){
|
||||
private static final long serialVersionUID = 2638082961277241764L;
|
||||
@Override
|
||||
public Object getTypedElementAt(int index) {
|
||||
public NPC getTypedElementAt(int index) {
|
||||
return project.getNPC(index);
|
||||
}
|
||||
@Override
|
||||
@@ -315,7 +485,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
final GDEComboModel<ActorCondition> comboModel = new GDEComboModel<ActorCondition>(proj, acond){
|
||||
private static final long serialVersionUID = 2638082961277241764L;
|
||||
@Override
|
||||
public Object getTypedElementAt(int index) {
|
||||
public ActorCondition getTypedElementAt(int index) {
|
||||
return project.getActorCondition(index);
|
||||
}
|
||||
@Override
|
||||
@@ -330,7 +500,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
final GDEComboModel<Item> comboModel = new GDEComboModel<Item>(proj, item){
|
||||
private static final long serialVersionUID = 2638082961277241764L;
|
||||
@Override
|
||||
public Object getTypedElementAt(int index) {
|
||||
public Item getTypedElementAt(int index) {
|
||||
return project.getItem(index);
|
||||
}
|
||||
@Override
|
||||
@@ -345,7 +515,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
final GDEComboModel<ItemCategory> comboModel = new GDEComboModel<ItemCategory>(proj, ic){
|
||||
private static final long serialVersionUID = 2638082961277241764L;
|
||||
@Override
|
||||
public Object getTypedElementAt(int index) {
|
||||
public ItemCategory getTypedElementAt(int index) {
|
||||
return project.getItemCategory(index);
|
||||
}
|
||||
@Override
|
||||
@@ -360,7 +530,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
final GDEComboModel<Quest> comboModel = new GDEComboModel<Quest>(proj, quest){
|
||||
private static final long serialVersionUID = 2638082961277241764L;
|
||||
@Override
|
||||
public Object getTypedElementAt(int index) {
|
||||
public Quest getTypedElementAt(int index) {
|
||||
return project.getQuest(index);
|
||||
}
|
||||
@Override
|
||||
@@ -375,7 +545,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
final GDEComboModel<Droplist> comboModel = new GDEComboModel<Droplist>(proj, droplist){
|
||||
private static final long serialVersionUID = 2638082961277241764L;
|
||||
@Override
|
||||
public Object getTypedElementAt(int index) {
|
||||
public Droplist getTypedElementAt(int index) {
|
||||
return project.getDroplist(index);
|
||||
}
|
||||
@Override
|
||||
@@ -390,7 +560,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
final GDEComboModel<Dialogue> comboModel = new GDEComboModel<Dialogue>(proj, dialogue){
|
||||
private static final long serialVersionUID = 2638082961277241764L;
|
||||
@Override
|
||||
public Object getTypedElementAt(int index) {
|
||||
public Dialogue getTypedElementAt(int index) {
|
||||
return project.getDialogue(index);
|
||||
}
|
||||
@Override
|
||||
@@ -405,7 +575,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
final GDEComboModel<TMXMap> comboModel = new GDEComboModel<TMXMap>(proj, map){
|
||||
private static final long serialVersionUID = 2638082961277241764L;
|
||||
@Override
|
||||
public Object getTypedElementAt(int index) {
|
||||
public TMXMap getTypedElementAt(int index) {
|
||||
return project.getMap(index);
|
||||
}
|
||||
@Override
|
||||
@@ -416,6 +586,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
return addGDEBox(pane, label, map, TMXMap.class, comboModel, writable, listener);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public MyComboBox addGDEBox(JPanel pane, String label, GameDataElement gde, final Class<? extends GameDataElement> dataClass, final GDEComboModel<? extends GameDataElement> comboModel, final boolean writable, final FieldUpdateListener listener) {
|
||||
JPanel gdePane = new JPanel();
|
||||
gdePane.setLayout(new JideBoxLayout(gdePane, JideBoxLayout.LINE_AXIS, 6));
|
||||
@@ -482,7 +653,63 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
return gdeBox;
|
||||
}
|
||||
|
||||
public JComboBox<QuestStage> addQuestStageBox(JPanel pane, Project proj, String label, Integer initialValue, boolean writable, final FieldUpdateListener listener, Quest quest, final JComboBox questSelectionBox) {
|
||||
JPanel gdePane = new JPanel();
|
||||
gdePane.setLayout(new JideBoxLayout(gdePane, JideBoxLayout.LINE_AXIS, 6));
|
||||
JLabel gdeLabel = new JLabel(label);
|
||||
gdePane.add(gdeLabel, JideBoxLayout.FIX);
|
||||
|
||||
QuestStage initial = null;
|
||||
if (quest != null) {
|
||||
initial = quest.getStage(initialValue);
|
||||
}
|
||||
final QuestStageComboModel comboModel = new QuestStageComboModel(proj, initial, quest);
|
||||
final JComboBox<QuestStage> combo = new JComboBox<QuestStage>(comboModel);
|
||||
combo.setRenderer(new GDERenderer(false, writable));
|
||||
new ComboBoxSearchable(combo){
|
||||
@Override
|
||||
protected String convertElementToString(Object object) {
|
||||
if (object == null) return "none";
|
||||
else return ((GameDataElement)object).getDesc();
|
||||
}
|
||||
};
|
||||
questSelectionBox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (comboModel.selected != null) {
|
||||
Editor.this.target.removeBacklink(comboModel.selected);
|
||||
}
|
||||
Quest newQuest = (Quest) questSelectionBox.getSelectedItem();
|
||||
comboModel.changeQuest(newQuest);
|
||||
combo.revalidate();
|
||||
}
|
||||
});
|
||||
combo.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
listener.valueChanged(combo, comboModel.selected == null ? null : comboModel.selected.progress);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
combo.setEnabled(writable);
|
||||
gdePane.add(combo, JideBoxLayout.VARY);
|
||||
|
||||
pane.add(gdePane, JideBoxLayout.FIX);
|
||||
|
||||
return combo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public JList addBacklinksList(JPanel pane, GameDataElement gde) {
|
||||
return addBacklinksList(pane, gde, "Elements linking to this one");
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public JList addBacklinksList(JPanel pane, GameDataElement gde, String title) {
|
||||
final JList list = new JList(new GDEBacklinksListModel(gde));
|
||||
list.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
@@ -503,7 +730,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
}
|
||||
});
|
||||
list.setCellRenderer(new GDERenderer(true, false));
|
||||
CollapsiblePanel colPane = new CollapsiblePanel("Elements linking to this one");
|
||||
CollapsiblePanel colPane = new CollapsiblePanel(title);
|
||||
colPane.setLayout(new JideBoxLayout(colPane, JideBoxLayout.PAGE_AXIS));
|
||||
colPane.add(new JScrollPane(list), JideBoxLayout.FIX);
|
||||
colPane.add(new JPanel(), JideBoxLayout.FIX);
|
||||
@@ -514,7 +741,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
return list;
|
||||
}
|
||||
|
||||
public static abstract class GDEComboModel<E extends GameDataElement> extends AbstractListModel implements ComboBoxModel {
|
||||
public static abstract class GDEComboModel<E extends GameDataElement> extends AbstractListModel<E> implements ComboBoxModel<E> {
|
||||
|
||||
private static final long serialVersionUID = -5854574666510314715L;
|
||||
|
||||
@@ -530,14 +757,14 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
public abstract int getSize();
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int index) {
|
||||
public E getElementAt(int index) {
|
||||
if (index == 0) {
|
||||
return null;
|
||||
}
|
||||
return getTypedElementAt(index - 1);
|
||||
}
|
||||
|
||||
public abstract Object getTypedElementAt(int index);
|
||||
public abstract E getTypedElementAt(int index);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
@@ -573,6 +800,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
this.writable = writable;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
@@ -580,9 +808,25 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
label.setText("None"+(writable ? ". Click on the button to create one." : ""));
|
||||
} else {
|
||||
if (includeType && ((GameDataElement)value).getDataType() != null) {
|
||||
label.setText(((GameDataElement)value).getDataType().toString()+"/"+((GameDataElement)value).getDesc());
|
||||
if (value instanceof QuestStage) {
|
||||
String text = ((GameDataElement)value).getDesc();
|
||||
if (text.length() > 60) {
|
||||
text = text.substring(0, 57)+"...";
|
||||
}
|
||||
label.setText(((GameDataElement)value).getDataType().toString()+"/"+((Quest)((QuestStage)value).parent).id+":"+text);
|
||||
} else {
|
||||
label.setText(((GameDataElement)value).getDataType().toString()+"/"+((GameDataElement)value).getDesc());
|
||||
}
|
||||
} else {
|
||||
label.setText(((GameDataElement)value).getDesc());
|
||||
if (value instanceof QuestStage) {
|
||||
String text = ((GameDataElement)value).getDesc();
|
||||
if (text.length() > 60) {
|
||||
text = text.substring(0, 57)+"...";
|
||||
}
|
||||
label.setText(text);
|
||||
} else {
|
||||
label.setText(((GameDataElement)value).getDesc());
|
||||
}
|
||||
}
|
||||
if (((GameDataElement)value).getIcon() == null) {
|
||||
Notification.addError("Unable to find icon for "+((GameDataElement)value).getDesc());
|
||||
@@ -595,7 +839,66 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
|
||||
}
|
||||
|
||||
public static class GDEBacklinksListModel implements ListModel {
|
||||
public static class QuestStageComboModel extends AbstractListModel<QuestStage> implements ComboBoxModel<QuestStage> {
|
||||
|
||||
private static final long serialVersionUID = -5854574666510314715L;
|
||||
|
||||
public Project project;
|
||||
public Quest currentQuest;
|
||||
public QuestStage selected;
|
||||
|
||||
public QuestStageComboModel(Project proj, QuestStage initial, Quest quest) {
|
||||
this.project = proj;
|
||||
this.currentQuest = quest;
|
||||
this.selected = initial;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
if (currentQuest == null) return 1;
|
||||
return currentQuest.stages.size()+1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QuestStage getElementAt(int index) {
|
||||
if (index == 0) {
|
||||
return null;
|
||||
}
|
||||
return currentQuest.stages.get(index - 1);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void setSelectedItem(Object anItem) {
|
||||
selected = (QuestStage) anItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSelectedItem() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
public void itemAdded(QuestStage item, int index) {
|
||||
fireIntervalAdded(this, index, index);
|
||||
}
|
||||
|
||||
public void itemRemoved(QuestStage item, int index) {
|
||||
fireIntervalRemoved(this, index, index);
|
||||
}
|
||||
|
||||
public void changeQuest(Quest newQuest) {
|
||||
int size = getSize();
|
||||
currentQuest = null;
|
||||
selected = null;
|
||||
fireIntervalRemoved(this, 1, size);
|
||||
currentQuest = newQuest;
|
||||
fireIntervalAdded(this, 1, getSize());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class GDEBacklinksListModel implements ListModel<GameDataElement> {
|
||||
|
||||
GameDataElement source;
|
||||
|
||||
@@ -620,7 +923,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int index) {
|
||||
public GameDataElement getElementAt(int index) {
|
||||
for (GameDataElement gde : source.getBacklinks()) {
|
||||
if (index == 0) return gde;
|
||||
index --;
|
||||
@@ -628,7 +931,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
|
||||
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
|
||||
|
||||
@Override
|
||||
public void addListDataListener(ListDataListener l) {
|
||||
@@ -647,6 +950,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class MyComboBox extends JComboBox implements ProjectElementListener {
|
||||
|
||||
private static final long serialVersionUID = -4184228604170642567L;
|
||||
@@ -659,13 +963,11 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
Editor.this.addElementListener(dataType, this);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public void elementAdded(GameDataElement added, int index) {
|
||||
((GDEComboModel)getModel()).itemAdded(added, index);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public void elementRemoved(GameDataElement removed, int index) {
|
||||
((GDEComboModel)getModel()).itemRemoved(removed, index);
|
||||
@@ -729,7 +1031,5 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.gpl.rpg.atcontentstudio.ui;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.Action;
|
||||
@@ -22,6 +22,7 @@ import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
|
||||
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
|
||||
import com.gpl.rpg.atcontentstudio.model.saves.SavedGame;
|
||||
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
|
||||
import com.gpl.rpg.atcontentstudio.model.tools.writermode.WriterModeData;
|
||||
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.ActorConditionEditor;
|
||||
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.DialogueEditor;
|
||||
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.DroplistEditor;
|
||||
@@ -33,13 +34,14 @@ import com.gpl.rpg.atcontentstudio.ui.map.TMXMapEditor;
|
||||
import com.gpl.rpg.atcontentstudio.ui.map.WorldMapEditor;
|
||||
import com.gpl.rpg.atcontentstudio.ui.saves.SavedGameEditor;
|
||||
import com.gpl.rpg.atcontentstudio.ui.sprites.SpritesheetEditor;
|
||||
import com.gpl.rpg.atcontentstudio.ui.tools.writermode.WriterModeEditor;
|
||||
import com.jidesoft.swing.JideTabbedPane;
|
||||
|
||||
public class EditorsArea extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = 8801849846876081538L;
|
||||
|
||||
private Map<Object, Editor> editors = new HashMap<Object, Editor>();
|
||||
private Map<Object, Editor> editors = new LinkedHashMap<Object, Editor>();
|
||||
private JideTabbedPane tabHolder;
|
||||
|
||||
public EditorsArea() {
|
||||
@@ -155,6 +157,15 @@ public class EditorsArea extends JPanel {
|
||||
openEditor(new WorldMapEditor(node));
|
||||
}
|
||||
|
||||
public void openEditor(WriterModeData node) {
|
||||
if (editors.containsKey(node)) {
|
||||
tabHolder.setSelectedComponent(editors.get(node));
|
||||
return;
|
||||
}
|
||||
node.link();
|
||||
openEditor(new WriterModeEditor(node));
|
||||
}
|
||||
|
||||
public void closeEditor(ProjectTreeNode node) {
|
||||
if (editors.containsKey(node)) {
|
||||
closeEditor(editors.get(node));
|
||||
|
||||
100
src/com/gpl/rpg/atcontentstudio/ui/IdChangeImpactWizard.java
Normal file
@@ -0,0 +1,100 @@
|
||||
package com.gpl.rpg.atcontentstudio.ui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.ATContentStudio;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
|
||||
import com.jidesoft.swing.JideBoxLayout;
|
||||
|
||||
public class IdChangeImpactWizard extends JDialog {
|
||||
|
||||
private static final long serialVersionUID = 8532169707953315739L;
|
||||
|
||||
public static enum Result {
|
||||
ok, cancel
|
||||
}
|
||||
|
||||
Result result = null;
|
||||
|
||||
private IdChangeImpactWizard(GameDataElement changing, List<GameDataElement> toModify, List<GameDataElement> toAlter) {
|
||||
super(ATContentStudio.frame, true);
|
||||
JPanel pane = new JPanel();
|
||||
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS));
|
||||
|
||||
pane.add(new JLabel("Changing the id for \""+changing.getDesc()+"\" has impacts on your project:"), JideBoxLayout.FIX);
|
||||
pane.add(new JLabel("The following elements from your project will be modified:"), JideBoxLayout.FIX);
|
||||
JList<GameDataElement> modifList = new JList<GameDataElement>(new Vector<GameDataElement>(toModify));
|
||||
modifList.setCellRenderer(new ChangeImpactListCellRenderer());
|
||||
pane.add(new JScrollPane(modifList), JideBoxLayout.FIX);
|
||||
pane.add(new JLabel("The following elements from the game source will be altered:"), JideBoxLayout.FIX);
|
||||
JList<GameDataElement> alterList = new JList<GameDataElement>(new Vector<GameDataElement>(toAlter));
|
||||
alterList.setCellRenderer(new ChangeImpactListCellRenderer());
|
||||
pane.add(new JScrollPane(alterList), JideBoxLayout.FIX);
|
||||
pane.add(new JLabel("Press Ok to apply the changes, or Cancel to cancel your edition of the object's ID"), JideBoxLayout.FIX);
|
||||
|
||||
JPanel buttonPane = new JPanel();
|
||||
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS));
|
||||
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
|
||||
JButton cancelButton = new JButton("Cancel");
|
||||
cancelButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
result = Result.cancel;
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
buttonPane.add(cancelButton, JideBoxLayout.FIX);
|
||||
JButton okButton = new JButton("Ok");
|
||||
okButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
result = Result.ok;
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
buttonPane.add(okButton, JideBoxLayout.FIX);
|
||||
pane.add(buttonPane, JideBoxLayout.FIX);
|
||||
getContentPane().setLayout(new BorderLayout());
|
||||
getContentPane().add(pane, BorderLayout.CENTER);
|
||||
pack();
|
||||
}
|
||||
|
||||
|
||||
public static Result showIdChangeImapctWizard(GameDataElement changing, List<GameDataElement> toModify, List<GameDataElement> toAlter) {
|
||||
IdChangeImpactWizard wizard = new IdChangeImpactWizard(changing, toModify, toAlter);
|
||||
wizard.setVisible(true);
|
||||
return wizard.result;
|
||||
}
|
||||
|
||||
public class ChangeImpactListCellRenderer extends DefaultListCellRenderer {
|
||||
private static final long serialVersionUID = 5764079243906396333L;
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
if (c instanceof JLabel) {
|
||||
JLabel label = (JLabel) c;
|
||||
GameDataElement target = ((GameDataElement)value);
|
||||
label.setIcon(new ImageIcon(target.getIcon()));
|
||||
label.setText(target.getDataType().toString()+"/"+target.getDesc());
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,8 +8,8 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
@@ -27,6 +27,7 @@ import javax.swing.event.ListDataListener;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.ATContentStudio;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement.State;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource;
|
||||
import com.gpl.rpg.atcontentstudio.model.Project;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
|
||||
@@ -58,6 +59,7 @@ public class JSONCreationWizard extends JDialog {
|
||||
|
||||
private JSONElement creation = null;
|
||||
final JLabel message;
|
||||
@SuppressWarnings("rawtypes")
|
||||
final JComboBox dataTypeCombo;
|
||||
final JTextField idField;
|
||||
final JTextField nameField;
|
||||
@@ -84,6 +86,7 @@ public class JSONCreationWizard extends JDialog {
|
||||
dataTypeCombo.setEnabled(false);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public JSONCreationWizard(final Project proj) {
|
||||
super(ATContentStudio.frame);
|
||||
this.proj = proj;
|
||||
@@ -293,6 +296,7 @@ public class JSONCreationWizard extends JDialog {
|
||||
creation.id = idField.getText();
|
||||
JSONCreationWizard.this.setVisible(false);
|
||||
JSONCreationWizard.this.dispose();
|
||||
creation.state = State.created;
|
||||
proj.createElement(creation);
|
||||
notifyCreated();
|
||||
ATContentStudio.frame.selectInTree(creation);
|
||||
@@ -499,6 +503,7 @@ public class JSONCreationWizard extends JDialog {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static class DataTypeComboModel implements ComboBoxModel {
|
||||
|
||||
DataType selected = DataType.none;
|
||||
@@ -513,7 +518,7 @@ public class JSONCreationWizard extends JDialog {
|
||||
return DataType.values()[index];
|
||||
}
|
||||
|
||||
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
|
||||
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
|
||||
|
||||
@Override
|
||||
public void addListDataListener(ListDataListener l) {
|
||||
@@ -540,7 +545,7 @@ public class JSONCreationWizard extends JDialog {
|
||||
private static final long serialVersionUID = 5621373849299980998L;
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
if (c instanceof JLabel) {
|
||||
((JLabel)c).setText(JSONCreationWizard.dataTypeDesc((DataType) value));
|
||||
@@ -579,7 +584,7 @@ public class JSONCreationWizard extends JDialog {
|
||||
public void elementCreated(JSONElement created);
|
||||
}
|
||||
|
||||
private List<CreationCompletedListener> listeners = new ArrayList<JSONCreationWizard.CreationCompletedListener>();
|
||||
private List<CreationCompletedListener> listeners = new CopyOnWriteArrayList<JSONCreationWizard.CreationCompletedListener>();
|
||||
|
||||
public void addCreationListener(CreationCompletedListener l) {
|
||||
listeners.add(l);
|
||||
|
||||
@@ -15,6 +15,7 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.ComboBoxModel;
|
||||
@@ -75,6 +76,7 @@ public class JSONImportWizard extends JDialog {
|
||||
|
||||
JPanel pane;
|
||||
JLabel message;
|
||||
@SuppressWarnings("rawtypes")
|
||||
JComboBox dataTypeCombo;
|
||||
JRadioButton importFromFile;
|
||||
JRadioButton importPasted;
|
||||
@@ -83,11 +85,13 @@ public class JSONImportWizard extends JDialog {
|
||||
JButton browse;
|
||||
RSyntaxTextArea jsonPasteArea;
|
||||
JScrollPane scroller;
|
||||
@SuppressWarnings("rawtypes")
|
||||
JList createdPreview;
|
||||
JPanel buttonPane;
|
||||
JButton ok, cancel;
|
||||
ActionListener okListener, cancelListener;
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public JSONImportWizard(Project proj) {
|
||||
|
||||
super(ATContentStudio.frame);
|
||||
@@ -334,6 +338,7 @@ public class JSONImportWizard extends JDialog {
|
||||
} else if (existingNode.getDataType() == GameSource.Type.altered) {
|
||||
errors.add("An item with id "+node.id+" is already altered in this project.");
|
||||
} else {
|
||||
node.jsonFile = existingNode.jsonFile;
|
||||
warnings.add("An item with id "+node.id+" exists in the used game source. This one will be inserted as \"altered\"");
|
||||
}
|
||||
existingNode = null;
|
||||
@@ -390,6 +395,7 @@ public class JSONImportWizard extends JDialog {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void showImportPreviewScreen(final List<JSONElement> created) {
|
||||
pane.removeAll();
|
||||
message.setText("The following data has been found. Click \"Ok\" to confirm.");
|
||||
@@ -404,13 +410,10 @@ public class JSONImportWizard extends JDialog {
|
||||
okListener = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JSONElement lastNode = null;
|
||||
for (JSONElement node : created) {
|
||||
proj.createElement(node);
|
||||
lastNode = node;
|
||||
}
|
||||
proj.createElements(created);
|
||||
JSONElement lastNode = created.get(created.size() - 1);
|
||||
if (lastNode != null) {
|
||||
lastNode.save();
|
||||
// lastNode.save();
|
||||
ATContentStudio.frame.selectInTree(lastNode);
|
||||
}
|
||||
JSONImportWizard.this.setVisible(false);
|
||||
@@ -432,6 +435,7 @@ public class JSONImportWizard extends JDialog {
|
||||
pane.repaint();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void showErrorScreen(List<String> errors) {
|
||||
pane.removeAll();
|
||||
message.setText("Failed to import. The following error(s) have been encountered:");
|
||||
@@ -464,6 +468,7 @@ public class JSONImportWizard extends JDialog {
|
||||
pane.repaint();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void showWarningScreen(List<String> warnings, final List<JSONElement> created) {
|
||||
pane.removeAll();
|
||||
message.setText("The following warnings(s) were raised while importing:");
|
||||
@@ -511,7 +516,7 @@ public class JSONImportWizard extends JDialog {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
if (value == null) {
|
||||
label.setText("none");
|
||||
@@ -555,7 +560,7 @@ public class JSONImportWizard extends JDialog {
|
||||
public static class ErrorRenderer extends DefaultListCellRenderer {
|
||||
private static final long serialVersionUID = -4265342800284721660L;
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
if (c instanceof JLabel) {
|
||||
((JLabel)c).setIcon(NotificationsPane.icons.get(Notification.Type.ERROR));
|
||||
@@ -568,7 +573,7 @@ public class JSONImportWizard extends JDialog {
|
||||
public static class WarningRenderer extends DefaultListCellRenderer {
|
||||
private static final long serialVersionUID = -3836045237946111606L;
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
if (c instanceof JLabel) {
|
||||
((JLabel)c).setIcon(NotificationsPane.icons.get(Notification.Type.WARN));
|
||||
@@ -577,6 +582,7 @@ public class JSONImportWizard extends JDialog {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static class GDEListModel implements ListModel {
|
||||
|
||||
List<? extends Object> source;
|
||||
@@ -599,7 +605,7 @@ public class JSONImportWizard extends JDialog {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
|
||||
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
|
||||
|
||||
@Override
|
||||
public void addListDataListener(ListDataListener l) {
|
||||
@@ -620,6 +626,7 @@ public class JSONImportWizard extends JDialog {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static class DataTypeComboModel implements ComboBoxModel {
|
||||
|
||||
DataType selected = DataType.none;
|
||||
@@ -634,7 +641,7 @@ public class JSONImportWizard extends JDialog {
|
||||
return DataType.values()[index];
|
||||
}
|
||||
|
||||
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
|
||||
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
|
||||
|
||||
@Override
|
||||
public void addListDataListener(ListDataListener l) {
|
||||
@@ -661,7 +668,7 @@ public class JSONImportWizard extends JDialog {
|
||||
private static final long serialVersionUID = 5621373849299980998L;
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
if (c instanceof JLabel) {
|
||||
((JLabel)c).setText(dataTypeDesc((DataType) value));
|
||||
|
||||
@@ -3,13 +3,11 @@ package com.gpl.rpg.atcontentstudio.ui;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
@@ -24,29 +22,22 @@ import com.gpl.rpg.atcontentstudio.Notification;
|
||||
import com.gpl.rpg.atcontentstudio.NotificationListener;
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class NotificationsPane extends JList {
|
||||
|
||||
private static final long serialVersionUID = -1100364214372392608L;
|
||||
|
||||
public static final String success_img_name = "/com/gpl/rpg/atcontentstudio/img/success.png";
|
||||
public static final String info_img_name = "/com/gpl/rpg/atcontentstudio/img/info.png";
|
||||
public static final String warn_img_name = "/com/gpl/rpg/atcontentstudio/img/warn.png";
|
||||
public static final String error_img_name = "/com/gpl/rpg/atcontentstudio/img/error.png";
|
||||
|
||||
public static final Map<Notification.Type, Icon> icons = new HashMap<Notification.Type, Icon>(Notification.Type.values().length);
|
||||
public static final Map<Notification.Type, Icon> icons = new LinkedHashMap<Notification.Type, Icon>(Notification.Type.values().length);
|
||||
|
||||
static {
|
||||
try {
|
||||
icons.put(Notification.Type.SUCCESS, new ImageIcon(ImageIO.read(NotificationsPane.class.getResourceAsStream(success_img_name))));
|
||||
icons.put(Notification.Type.INFO, new ImageIcon(ImageIO.read(NotificationsPane.class.getResourceAsStream(info_img_name))));
|
||||
icons.put(Notification.Type.WARN, new ImageIcon(ImageIO.read(NotificationsPane.class.getResourceAsStream(warn_img_name))));
|
||||
icons.put(Notification.Type.ERROR, new ImageIcon(ImageIO.read(NotificationsPane.class.getResourceAsStream(error_img_name))));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
icons.put(Notification.Type.SUCCESS, new ImageIcon(DefaultIcons.getStatusGreenIcon()));
|
||||
icons.put(Notification.Type.INFO, new ImageIcon(DefaultIcons.getStatusBlueIcon()));
|
||||
icons.put(Notification.Type.WARN, new ImageIcon(DefaultIcons.getStatusOrangeIcon()));
|
||||
icons.put(Notification.Type.ERROR, new ImageIcon(DefaultIcons.getStatusRedIcon()));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public NotificationsPane() {
|
||||
super();
|
||||
MyListModel model = new MyListModel();
|
||||
@@ -99,7 +90,7 @@ public class NotificationsPane extends JList {
|
||||
}
|
||||
}
|
||||
|
||||
private List<ListDataListener> listeners = new ArrayList<ListDataListener>();
|
||||
private List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
|
||||
@Override
|
||||
public void addListDataListener(ListDataListener l) {
|
||||
listeners.add(l);
|
||||
|
||||