public short y;
public short width;
public short height;
- public short[] map;
+ // TODO: decide whether i want a ground layer, or entities to contain the layer they're rendered on
+ // Latter is more flexible.
+ public short groundLayer;
+ public short layerCount;
+ public short[][] map;
public MapMessage() {
}
- public MapMessage(int name, int width, int height, int locx, int locy, short[] map) {
+ public MapMessage(int name, int width, int height, int locx, int locy, int groundLayer, int layerCount, short[][] map) {
super(name);
this.x = (short) locx;
this.y = (short) locy;
this.width = (short) width;
this.height = (short) height;
+ this.groundLayer = (short)groundLayer;
+ this.layerCount = (short)layerCount;
this.map = map;
}
ostream.writeShort(y);
ostream.writeShort(width);
ostream.writeShort(height);
- for (int i = 0; i < width * height; i++)
- ostream.writeShort(map[i]);
+ ostream.writeShort(groundLayer);
+ ostream.writeShort(layerCount);
+ for (int l = 0; l < layerCount; l++) {
+ short[] layer = map[l];
+ for (int i = 0; i < width * height; i++)
+ ostream.writeShort(layer[i]);
+ }
}
@Override
y = istream.readShort();
width = istream.readShort();
height = istream.readShort();
+ groundLayer = istream.readShort();
+ layerCount = istream.readShort();
len = width * height;
- map = new short[len];
- for (int i = 0; i < len; i++) {
- map[i] = istream.readShort();
+ map = new short[layerCount][];
+ for (int l = 0; l < layerCount; l++) {
+ short[] layer = new short[width * height];
+ map[l] = layer;
+ for (int i = 0; i < len; i++) {
+ layer[i] = istream.readShort();
+ }
}
}
import duskz.io.tiled.Image;
import duskz.io.tiled.Layer;
import duskz.io.tiled.Map;
+import duskz.io.tiled.Properties;
import duskz.io.tiled.Property;
import duskz.io.tiled.Tile;
import duskz.io.tiled.Tileset;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import javax.xml.bind.Unmarshaller;
/**
- * Tiled loader/converter. This is only experimental at this stage.
+ * Tiled loader/converter. This is only experimental at this stage.
*
* @author notzed
*/
Logger.getLogger(Tiled.class.getName()).log(Level.SEVERE, null, ex);
}
}
+
+ static void tiledToDusk(File src, File dst) throws IOException {
+ try {
+ JAXBContext jc = JAXBContext.newInstance(Map.class);
+ Unmarshaller u = jc.createUnmarshaller();
+ Map tmap = (Map) u.unmarshal(src);
+
+ System.out.println("Loaded map size: " + tmap.getWidth() + "x" + tmap.getHeight());
+
+ List<TileInfo> tileInfo = new ArrayList<>();
+ int tid = 0;
+
+ // TODO: write out tileset info somewhere
+
+
+ TileMap map = new TileMap(tmap.getWidth(), tmap.getHeight());
+
+ int lid = 0;
+
+ int nlayers = 0;
+ int groundid = 0;
+ int twidth = 0;
+ int theight = 0;
+ for (Object o : tmap.getLayerOrObjectgroup()) {
+ if (o instanceof Layer) {
+ Layer l = (Layer) o;
+
+ if (l.getName() != null && l.getName().equals("ground")) {
+ twidth = l.getWidth();
+ theight = l.getHeight();
+ groundid = nlayers;
+ }
+
+ nlayers++;
+ }
+ }
+
+ System.out.printf("Found %d layers\n", nlayers);
+ System.out.printf("Ground on layer %d\n", groundid);
+ // Create map
+ try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(dst))) {
+ // Write header
+ dos.writeInt(TileMap.MAGIC_LAYERED);
+ dos.writeInt(0);
+ dos.writeInt(0);
+ dos.writeInt(twidth);
+ dos.writeInt(theight);
+ dos.writeInt(groundid);
+ dos.writeInt(nlayers);
+
+ int layerid = 0;
+ for (Object o : tmap.getLayerOrObjectgroup()) {
+ if (o instanceof Layer) {
+ Layer l = (Layer) o;
+ int lwidth = l.getWidth();
+ int lheight = l.getHeight();
+ int len = l.getWidth() * l.getHeight();
+ int layer[] = new int[len];
+
+ // Read in layer and perform some optimisation on it
+ try (ImageInputStream dis = new MemoryCacheImageInputStream(decodeArray(l.getData().getvalue()))) {
+ dis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+ for (int i = 0; i < len; i++) {
+ layer[i] = dis.readInt();
+ }
+
+ }
+
+ // Find bounds of used squares (if not ground layer)
+ int minx = lwidth - 1;
+ int maxx = 0;
+ int miny = lheight - 1;
+ int maxy = 0;
+
+ if (layerid != groundid) {
+ for (int y = 0; y < lheight; y++) {
+ for (int x = 0; x < lwidth; x++) {
+ if (layer[x + y * lwidth] != 0) {
+ minx = Math.min(x, minx);
+ miny = Math.min(y, miny);
+ maxx = Math.max(x, maxx);
+ maxy = Math.max(y, maxy);
+ }
+ }
+ }
+ } else {
+ minx = 0;
+ maxx = lwidth - 1;
+ miny = 0;
+ maxy = lheight - 1;
+ }
+
+ System.out.printf("Writing layer %d '%s' at %d,%d size %d,%d\n",
+ layerid, l.getName(), minx, miny, maxx - minx + 1, maxy - miny + 1);
+
+ // Write out used area
+ dos.writeInt(minx);
+ dos.writeInt(miny);
+ dos.writeInt(maxx - minx + 1);
+ dos.writeInt(maxy - miny + 1);
+ for (int y = miny; y <= maxy; y++) {
+ for (int x = minx; x <= maxx; x++) {
+ dos.writeShort(layer[x + y * lwidth]);
+ }
+ }
+ }
+
+ layerid++;
+ }
+ }
+
+ } catch (JAXBException ex) {
+ Logger.getLogger(Tiled.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
// test load/save itled format map
public static void main(String[] args) throws IOException {
- testimport(new File("/home/notzed/house.tmx"),
- new File("/home/notzed/house.jar"));
+ //testimport(new File("/home/notzed/house.tmx"),
+ // new File("/home/notzed/house.jar"));
+ tiledToDusk(new File("/home/notzed/test-map.tmx"),
+ new File("/home/notzed/test-map.bin"));
//testexport();
}
}
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.FilePermission;
import java.io.IOException;
+import java.lang.reflect.ReflectPermission;
+import java.net.NetPermission;
import java.security.AccessControlContext;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.CodeSource;
+import java.security.Permission;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
+import java.util.Map.Entry;
+import java.util.PropertyPermission;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.Bindings;
+import javax.script.Compilable;
+import javax.script.CompiledScript;
+import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
}
}
+ public static class Hidden {
+
+ void none() {
+ System.out.println("none done");
+ }
+
+ public void tryPublic() {
+ System.out.println("public done");
+ }
+
+ private void tryPrivate() {
+ System.out.println("private done");
+ }
+ }
+
public static class Thing {
FileOutputStream fos;
}
}
+ public Hidden getHidden() {
+ return new Hidden();
+ }
+
public boolean isPet() {
return false;
}
}
}
}
+
+ static class ScriptManager extends SecurityManager {
+
+ @Override
+ public void checkSecurityAccess(String target) {
+ System.out.println("check security access: " + target);
+ super.checkSecurityAccess(target);
+ }
+
+ @Override
+ public void checkAccess(Thread t) {
+ System.out.println("Check access thread: " + t);
+ super.checkAccess(t);
+ }
+
+ @Override
+ public void checkAccess(ThreadGroup g) {
+ System.out.println("Check access threadgroup: " + g);
+ super.checkAccess(g);
+ }
+
+ @Override
+ public void checkDelete(String file) {
+ System.out.println("check delete");
+ super.checkDelete(file);
+ }
+
+ @Override
+ public void checkCreateClassLoader() {
+ System.out.println("checkcreateclassloader");
+ super.checkCreateClassLoader();
+ }
+
+ @Override
+ public void checkExec(String cmd) {
+ System.out.println("check exec: " + cmd);
+ super.checkExec(cmd);
+ }
+
+ @Override
+ public void checkExit(int status) {
+ System.out.println("check exit");
+ super.checkExit(status);
+ }
+
+ @Override
+ public void checkLink(String lib) {
+ System.out.println("checklink: " + lib);
+ super.checkLink(lib);
+ }
+
+ @Override
+ public void checkPackageDefinition(String pkg) {
+ System.out.println("check package deifnition: " + pkg);
+ super.checkPackageDefinition(pkg);
+ }
+
+ @Override
+ public void checkMemberAccess(Class<?> clazz, int which) {
+ System.out.println("check member access: " + clazz + " " + which);
+ super.checkMemberAccess(clazz, which);
+ }
+
+ @Override
+ public void checkPackageAccess(String pkg) {
+ System.out.println("check package: " + pkg);
+ super.checkPackageAccess(pkg);
+
+ }
+
+ @Override
+ public void checkPermission(Permission perm) {
+ System.out.println("check permission: " + perm);
+
+ if (perm instanceof FilePermission) {
+ FilePermission fp = (FilePermission) perm;
+ String path = fp.getName();
+
+ // Check whitelist
+ if (path.startsWith("/usr/java"))
+ return;
+ } else if (perm instanceof NetPermission) {
+ NetPermission np = (NetPermission) perm;
+ String name = np.getName();
+
+ if (name.equals("specifyStreamHandler")) {
+ return;
+ }
+ } else if (perm instanceof PropertyPermission) {
+ PropertyPermission pp = (PropertyPermission) perm;
+ String name = pp.getName();
+
+ if (name.startsWith(("rhino."))) {
+ return;
+ }
+ return;
+ } else if (perm instanceof ReflectPermission) {
+ ReflectPermission rp = (ReflectPermission) perm;
+ int depth = 0;
+ System.out.println("bt\n");
+ for (StackTraceElement elem : Thread.currentThread().getStackTrace()) {
+ //System.out.println(" " + elem);
+ //if (elem.getClassName().equals("com.sun.script.javascript.RhinoScriptEngine");
+ System.out.println(" " + elem.getClassName() + " " + elem.getMethodName());
+
+ String cl = elem.getClassName();
+ String m = elem.getMethodName();
+ if (cl.equals("com.sun.script.javascript.RhinoScriptEngine")
+ && m.equals("getRuntimeScope")) {
+ depth++;
+ } else if (cl.equals("sun.org.mozilla.javascript.internal.NativeJavaMethod")
+ && m.equals("call")) {
+ depth++;
+ }
+ }
+ System.out.println("match depth = " + depth);
+ if (depth == 1)
+ return;
+ super.checkPermission(perm);
+ return;
+ }
+
+ //super.checkPermission(perm);
+ }
+
+ @Override
+ public void checkPermission(Permission perm, Object context) {
+ System.out.println("check permission: " + perm + " ctx: " + context);
+ super.checkPermission(perm, context);
+ }
+ }
+
+ static class ScriptLoader extends ClassLoader {
+
+ @Override
+ protected Package getPackage(String name) {
+ System.out.println("get package: " + name);
+ return super.getPackage(name);
+ }
+
+ @Override
+ protected Package[] getPackages() {
+ System.out.println("get packages");
+ return super.getPackages();
+ }
+
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ System.out.println("load class: " + name);
+ return super.loadClass(name);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ System.out.println("find class: " + name);
+ return super.findClass(name);
+ }
+ }
static ScriptEngine engine;
+ interface MobScript {
+ void onBattle(Thing thing);
+ //int getCost();
+ };
+
public static void main(String[] args) throws ScriptException, InterruptedException {
+ if (true) {
+ Thing thing = new Thing();
+ final ScriptEngineManager factory = new ScriptEngineManager();
+ engine = factory.getEngineByName("JavaScript");
+
+
+ engine.eval("a=1;");
+ engine.eval("println(a);");
+
+ String bob = ("var bob = {"
+ + " cost:1,\n"
+ + " description:'evil bob',\n"
+ + " onBattle: function(thing) {\n"
+ + "println('on battle!');\n"
+ + " }\n"
+ + "};\n"
+ + "");
+
+ Compilable comp = ((Compilable)engine);
+ CompiledScript cbob = comp.compile(bob);
+
+
+ engine.eval(bob);
+
+ engine.eval("var bob = {\n"
+ + "cost:1,\n"
+ + "description:'kind bob',\n"
+ + "onBattle: function(thing) {\n"
+ + " println('im a pacifist!');\n"
+ + "},"
+ + "onFlee: function(thing) {"
+ + "}"
+ + "}\n");
+
+
+ engine.eval(""
+ + "onBattle= function(thing) {"
+ + "println('on battle!');"
+ + " };"
+ + ""
+ + "");
+
+ //MobScript m = ((Invocable)engine).getInterface(MobScript.class);
+ //System.out.println("by interface");
+ //m.onBattle(thing);
+
+ engine.eval("var vars = { name: 'a', type: 'shit' };");
+
+ engine.eval("function a() { println('first a'); }");
+ engine.eval("a();");
+ engine.eval("function a() { println('second a'); }");
+ engine.eval("a();onBattle();");
+
+ System.out.println("bob.cost = " + engine.eval("bob.cost"));
+ System.out.println("bob.desc = " + engine.eval("bob.description"));
+
+ try {
+ Invocable iv = (Invocable)engine;
+ iv.invokeMethod(engine.get("bob"), "onBattle", thing);
+
+ MobScript a = ((Invocable)engine).getInterface(engine.get("bob"), MobScript.class);
+ System.out.print("foo - ");
+ a.onBattle(thing);
+ // System.out.println("cost? = " + a.getCost());
+ } catch (NoSuchMethodException ex) {
+ Logger.getLogger(Junk.class.getName()).log(Level.SEVERE, null, ex);
+ }
+
+ for (Entry<String, Object> e : engine.getBindings(ScriptContext.ENGINE_SCOPE).entrySet()) {
+ System.out.println("`" + e.getKey() + "'= " + e.getValue() + " " + e.getValue().getClass().getName());
+ }
+
+ System.out.println("vars = " + engine.eval("bob.toSource();"));
+
+ //engine.setContext(null);
+ return;
+ }
+ if (true) {
+ final ScriptLoader loader = new ScriptLoader();
+ final ScriptEngineManager factory = new ScriptEngineManager(loader);
+ engine = factory.getEngineByName("JavaScript");
+
+ System.setSecurityManager(new ScriptManager());
+
+ Permissions perms = new Permissions();
+ //perms.add(new RuntimePermission("accessClassInPackage.sun.util.resources"));
+ //perms.add(new AllPermission());
+ //perms.add(new FilePermission("hack.txt", "read,write"));
+ // perms.add(new NetPermission("*"));
+ //perms.add(new RuntimePermission("accessDeclaredMembers"));
+ //perms.add(new RuntimePermission("accessClassInPackage"));
+ // Cast to Certificate[] required because of ambiguity:
+ ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms);
+ AccessControlContext ac = new AccessControlContext(new ProtectionDomain[]{domain});
+
+ // This doesn't work: security permissions are lost in the next thing.
+ // bloody odd if you ask me
+ AccessController.doPrivileged(new PrivilegedAction<ScriptEngine>() {
+ void eval(String what) throws ScriptException {
+ System.out.println("\n\n****************\neval: " + what);
+ System.out.println();
+ engine.eval(what);
+ }
+
+ @Override
+ public ScriptEngine run() {
+ try {
+ System.out.println("start script\n");
+ engine.put("thing", new Thing());
+ // engine.eval("java.lang.System.out.println('system.out.println');");
+ //eval("thing.moveTo(1,1);");
+ eval("thing.getHidden().tryPublic();");
+ // eval("thing.getHidden().none();");
+ eval("thing.getHidden().tryPrivate();");
+
+ try (FileOutputStream fos = new FileOutputStream("hack-a")) {
+ fos.write(1);
+ System.out.println("wrote hack-a");
+ } catch (IOException x) {
+ x.printStackTrace();
+ } catch (AccessControlException x) {
+ x.printStackTrace(System.out);
+ }
+
+ return null;
+ } catch (SecurityException ex) {
+ ex.printStackTrace();
+ } catch (ScriptException ex) {
+ ex.printStackTrace();
+ }
+ return null;
+ }
+ }, ac);
+ return;
+ }
+ if (true) {
+ Thing thing = new Thing();
+
+ //System.setSecurityManager(new ScriptManager());
+
+ ScriptEngineManager factory = new ScriptEngineManager(new ScriptLoader());
+ engine = factory.getEngineByName("JavaScript");
+ engine.eval("java.lang.System.out.println('system.out.println');");
+
+ return;
+ }
//new Junk().chatMessage(null, 16, 16, null);
//new Junk().chatMessage(null, 2, 2, null);
// create a script engine manager
};
Thread t = new Thread(r);
t.start();
-
+
try {
engine.eval("println(\"hello world\");");
engine.eval("trigger.chat('this is a chat message from sandbox?');");
loadPrefs();
// Load Map
- File newmap = new File("shortmapx");
+ File newmap = new File("defMaps/main");
if (newmap.exists()) {
+ // FIXME: load multiple maps here
+ log.printMessage(Log.INFO, "Loading Layered Map...");
+ map = TileMap.loadLayered(newmap);
+ log.printMessage(Log.VERBOSE, map.getCols() + "x" + map.getRows() + "x" + map.getLayerCount());
+ } else if ((newmap = new File("shortmapx")).exists()) {
log.printMessage(Log.INFO, "Loading Map...");
map = TileMap.loadMapX(newmap);
log.printMessage(Log.VERBOSE, map.getCols() + "/" + map.getRows());
strOnDropScript = null;
public String strOnUseScript = null,
strOnWearScript = null,
- strOnUnWearScript = null,
- strOnOpenScript = null,
- strOnCloseScript = null,
- strOnAddItemScript = null,
- strOnRemoveItemScript = null;
+ strOnUnWearScript = null;
public int intCost,
intType = -1,
intKind = -1,
int width = r * 2 + 1;
int height = r * 2 + 1;
- short[] tiles = new short[width * height];
+ short[] tiles = null;
int i = 0;
- //System.out.printf("map at %d,%d\n", x, y);
- for (int my = y - r; my <= y + r; my++) {
- for (int mx = x - r; mx <= x + r; mx++) {
- tiles[i++] = game.map.inside(mx, my) ? game.map.getTile(mx, my) : 0;
- //System.out.printf("%s%3d", game.map.inside(mx, my) ? " " : "*", tiles[i-1]);
+ int nlayers = game.map.getLayerCount();
+ int nused = 0;
+ short[][] layers = new short[nlayers][];
+ int groundLayer = 0;
+ for (int l=0;l<nlayers;l++) {
+ if (tiles == null)
+ tiles = new short[width*height];
+
+ short[] visible = game.map.getRegion(l, x-r, y-r, width, height, tiles);
+
+ if (visible != null) {
+ tiles = null;
+
+ if (l == game.map.getGroundLayer())
+ groundLayer = nused;
+
+ layers[nused++] = visible;
}
- //System.out.println("\n");
}
-
- send(new MapMessage(MSG_UPDATE_MAP, width, height, x, y, tiles));
+
+ send(new MapMessage(MSG_UPDATE_MAP, width, height, x, y, groundLayer, nused, layers));
}
public void startBattle(LivingThing opponent) {
* Entities, they are chained off each other for efficiency reasons
*/
private DuskObject entities[];
+ /**
+ * Layers
+ */
+ private int groundLayer;
+ private TileLayer layers[];
/**
* privileges for each cell. This appears to be unimplemented in Dusk so
* isn't here either.
return cols;
}
+ public int getLayerCount() {
+ return layers.length;
+ }
+
+ public int getGroundLayer() {
+ return groundLayer;
+ }
+
public void saveMap(File path) throws IOException {
path.delete();
try (RandomAccessFile rafFile = new RandomAccessFile(path, "rw")) {
}
}
}
+
+ static class TileLayer {
+
+ int x, y;
+ int width, height;
+ private short[] tiles;
+
+ public TileLayer(int x, int y, int width, int height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.tiles = new short[width * height];
+ }
+
+ public TileLayer(int x, int y, int width, int height, short[] tiles) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.tiles = tiles;
+ }
+
+ public boolean inside(int tx, int ty) {
+ tx -= this.x;
+ ty -= this.y;
+ return tx >= 0 && tx < width
+ && ty >= 0 && ty < height;
+ }
+
+ public short getTile(int tx, int ty) {
+ tx -= this.x;
+ ty -= this.y;
+ if (tx >= 0 && tx < width
+ && ty >= 0 && ty < height) {
+ return tiles[tx + ty * width];
+ } else
+ return 0;
+ }
+ }
public static final int FORMAT_BYTE = 0;
public static final int FORMAT_SHORT = 1;
+ // 'mapz'
+ // TODO: gzip?
+ public static final int MAGIC_LAYERED = 0x7a70616d;
+
+ /**
+ * Load a layered map. Format is:
+ * magic: int
+ * version: int 0
+ * flags: int (0 - short)
+ * width: int must contain all layers
+ * height: int must contain all layers
+ * layer ground: int index of ground layer, ground layer must be same size as map
+ * layer count: int
+ * then layer count {
+ * layer x: int
+ * layer y: int
+ * layer width: int
+ * layer height: int
+ * layer data: short width*height in row major format
+ * }
+ *
+ * @param path
+ * @return
+ * @throws IOException
+ */
+ public static TileMap loadLayered(File path) throws IOException {
+ TileMap map;
+
+ try (DataInputStream mapFile = new DataInputStream(new FileInputStream(path))) {
+ int magic = mapFile.readInt();
+ int version = mapFile.readInt();
+ int flags = mapFile.readInt();
+ int cols = mapFile.readInt();
+ int rows = mapFile.readInt();
+ int groundLayer = mapFile.readInt();
+ int layerCount = mapFile.readInt();
+
+ if (magic != MAGIC_LAYERED
+ || version != 0) {
+ throw new IOException("Invalid format/magic/unknown version");
+ }
+
+ map = new TileMap(cols, rows);
+
+ map.groundLayer = groundLayer;
+ map.layers = new TileLayer[layerCount];
+ for (int l = 0; l < layerCount; l++) {
+ int tx = mapFile.readInt();
+ int ty = mapFile.readInt();
+ int twidth = mapFile.readInt();
+ int theight = mapFile.readInt();
+ TileLayer tl;
+
+ if (l == groundLayer)
+ tl = new TileLayer(tx, ty, twidth, theight, map.tiles);
+ else
+ tl = new TileLayer(tx, ty, twidth, theight);
+
+ map.layers[l] = tl;
+
+ for (int i = 0; i < twidth * theight; i++) {
+ tl.tiles[i] = mapFile.readShort();
+ }
+ }
+ }
+ return map;
+ }
// Map in row major format (i.e. more efficient)
public static TileMap loadMapX(File path) throws IOException {
map.setTile(x, y, mapFile.readShort());
}
}
+
+ map.layers = new TileLayer[1];
+ map.layers[0] = new TileLayer(0, 0, cols, rows, map.tiles);
}
return map;
}
map.setTile(x, y, mapFile.readShort());
}
}
+ map.layers = new TileLayer[1];
+ map.layers[0] = new TileLayer(0, 0, cols, rows, map.tiles);
}
return map;
}
&& y >= 0 && y < rows;
}
+ public boolean inside(int layer, int x, int y) {
+ return x >= 0 && x < cols
+ && y >= 0 && y < rows;
+ }
+
+ /**
+ * Calculate if the layer is empty over the given region
+ *
+ * @param layer
+ * @param x
+ * @param y
+ * @param width
+ * @param height
+ * @return
+ */
+ public boolean empty(int layer, int x, int y, int width, int height) {
+ TileLayer tl = layers[layer];
+
+ for (int ty = y; ty < y + height; ty++) {
+ for (int tx = x; tx < x + width; tx++) {
+ if (tl.getTile(tx, ty) != 0)
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Get the region bounded by the supplied coordinates.
+ * If the region is all empty, then null is returned.
+ *
+ * @param layer
+ * @param x
+ * @param y
+ * @param width
+ * @param height
+ * @param region if supplied use this array otherwise allocate one
+ * @return
+ */
+ public short[] getRegion(int layer, int tx, int ty, int width, int height, short[] region) {
+ TileLayer tl = layers[layer];
+ if (region == null)
+ region = new short[width * height];
+ boolean empty = true;
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ short t = tl.getTile(tx + x, ty + y);
+
+ region[x + width * y] = t;
+
+ empty &= t == 0;
+ }
+ }
+ if (empty)
+ return null;
+ else
+ return region;
+ }
+
public void setTile(int x, int y, int t) {
tiles[x + y * cols] = (short) t;
}
return tiles[x + y * cols];
}
+ public short getTile(int layer, int x, int y) {
+ return tiles[x + y * cols];
+ }
+
public synchronized List<DuskObject> getEntities(int x, int y, List<DuskObject> list) {
if (list == null)
list = new ArrayList<>();
public int x, y;
public final List<DuskObject> entities = new ArrayList<>();
+ // Tileid of ground layer
public short tile;
+ // Tileid of visible layers in correct order
+ public short[] layers = new short[TileMap.this.layers.length];
protected void setData(int x, int y) {
this.x = x;
} else {
this.tile = 0;
}
+ for (int l = 0; l < layers.length; l++) {
+ layers[l] = TileMap.this.layers[l].getTile(x, y);
+ }
}
}
*/
package duskz.client;
+import duskz.protocol.MapMessage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
* Offset of map (top-left corner)
*/
public int offx, offy;
+ /**
+ * Which level is currently the ground level
+ */
+ private int groundLevel;
/**
* Tile indices for images
*/
- private short[] tiles;
+ short[][] levels;
/**
* Entities by id
*/
this.cols = cols;
this.rows = rows;
- tiles = new short[cols * rows];
+ levels = new short[1][cols * rows];
+ groundLevel = 0;
}
public Collection<Entity> getEntities() {
}
public int getTile(int x, int y) {
- return tiles[x + y * cols];
+ return levels[groundLevel][x + y * cols];
+ }
+
+ public int getTile(int level, int x, int y) {
+ return levels[level][x + y * cols];
}
- public void setTile(int x, int y, int tile) {
- tiles[x + y * cols] = (short) tile;
+ public int getGroundLevel() {
+ return groundLevel;
+ }
+
+ public int getLevelCount() {
+ return levels.length;
}
private Integer locationKey(int x, int y) {
&& ly >= 0 && ly < rows;
}
- public synchronized void updateTiles(int offx, int offy, short[] tiles) throws IOException {
+ //public synchronized void updateTiles(int offx, int offy, short[] tiles) throws IOException {
+ public synchronized void updateTiles(MapMessage mm) throws IOException {
+
//for (int x = 0; x < cols; x++) {
// for (int y = 0; y < rows; y++) {
// setTile(x, y, Short.parseShort(instream.readLine()));
// }
//}
- if (tiles.length != rows * cols) {
+ if (mm.width != cols || mm.height != rows) {
throw new IOException("Protocol error incorrect map size");
}
- System.arraycopy(tiles, 0, this.tiles, 0, tiles.length);
- this.offx = offx;
- this.offy = offy;
+ //System.out.printf("Got map update %dx%d size %dx%dx%d\n", mm.x, mm.y, mm.width, mm.height, mm.layerCount);
+
+ this.levels = mm.map;
+ this.groundLevel = mm.groundLayer;
+ this.offx = mm.x - (cols - 1) / 2;
+ this.offy = mm.y - (rows - 1) / 2;
// Prune out of range thingies
List<Entity> removing = new ArrayList<>();
MapMessage mm = (MapMessage) dm;
status.updateLocation(mm.x, mm.y);
- map.updateTiles(mm.x - (map.cols - 1) / 2, mm.y - (map.rows - 1) / 2, mm.map);
+ map.updateTiles(mm);
update();
frame.setStatus(status);
//frame.info.setText("HP: " + inthp + "/" + intmaxhp + " MP: " + intsp + "/" + intmaxsp + " Loc: " + LocX + "/" + LocY);
}
});
}
- //DataManagerFX data;
- Image tileImage;
+ DataManagerFX data;
+ //Image tileImage;
int tileSize;
Image playerImage;
int playerSize;
@Override
public void setImages(String tiles, int tileSize, String players, int playerSize, String sprites, int spriteSize) {
- //try {
- System.out.println("set tile image");
- // FIXME: put sprites into data manager
- //data = new DataManagerFX("/home/notzed/house.jar");
- //data.open();
- tileImage = new Image(tiles, false);
- this.tileSize = tileSize;
- playerImage = new Image(players, false);
- this.playerSize = playerSize;
- spriteImage = new Image(sprites, false);
- this.spriteSize = spriteSize;
- //} catch (IOException ex) {
- // Logger.getLogger(MainFrameFX.class.getName()).log(Level.SEVERE, null, ex);
- //}
+ try {
+ System.out.println("set tile image");
+ // FIXME: put sprites into data manager
+ data = new DataManagerFX("/home/notzed/house.jar");
+ data.open();
+ //tileImage = new Image(tiles, false);
+ this.tileSize = tileSize;
+ playerImage = new Image(players, false);
+ this.playerSize = playerSize;
+ spriteImage = new Image(sprites, false);
+ this.spriteSize = spriteSize;
+ } catch (IOException ex) {
+ Logger.getLogger(MainFrameFX.class.getName()).log(Level.SEVERE, null, ex);
+ }
}
@Override
public void updateMap(ClientMap map) {
- // First ugly cut - just create a whole set of tiles
+ // Note this has map synchronized already
+
+ // Since we get a whole update for the map every time, there isn't much we
+ // can practically do apart from simply build a whole new page to display.
System.out.println("update map");
- //if (data == null) {
- if (tileImage == null) {
+ if (data == null) {
+ //if (tileImage == null) {
System.out.println("Map not ready yet");
return;
}
final ArrayList<Node> children = new ArrayList<>();
final ArrayList<Node> upper = new ArrayList<>();
+ int levelCount = map.getLevelCount();
// Build map
- for (int y = 0; y < map.rows; y++) {
- for (int x = 0; x < map.cols; x++) {
- ImageView iv = new ImageView(tileImage);
- int tileid = map.getTile(x, y);
- iv.setViewport(new Rectangle2D(tileid * tileSize, 0, tileSize, tileSize));
- iv.relocate(x * tileSize, y * tileSize);
- children.add(iv);
-
- //children.add(data.createTile(map.getTile(x, y), x, y, tileSize, tileSize));
-
- // TODO: names always? on top
- Collection<Entity> ents = map.getEntities(x + map.offx, y + map.offy);
- if (ents != null) {
- for (Entity e : ents) {
- drawEntity(e, map.offx, map.offy, children, upper);
+ for (int l = 0; l < levelCount; l++) {
+ for (int y = 0; y < map.rows; y++) {
+ // Draw tiles first for whole row
+ for (int x = 0; x < map.cols; x++) {
+ int tileid = map.getTile(l, x, y);
+ if (tileid != 0) {
+ children.add(data.createTile(tileid, x, y, tileSize, tileSize));
+ }
+ }
+
+ // Now check for entities over this layer row
+ if (l == map.getGroundLevel()) {
+ for (int x = 0; x < map.cols; x++) {
+ Collection<Entity> ents = map.getEntities(x + map.offx, y + map.offy);
+ if (ents != null) {
+ for (Entity e : ents) {
+ drawEntity(e, map.offx, map.offy, children, upper);
+ }
+ }
}
}
}