From c8d75f4d9277a0820a36db929b2495ca1a6794f4 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Thu, 2 Mar 2023 13:02:47 +1030 Subject: [PATCH] Fixes and improvements. Move to rhino for javascript, unable to get nashorn to work with modules. Change tile textures to be the size of the tile rather than sub-textures, previous caused significant performance issues. Change the tileset format and include sprites and player sprites. Merge in anim code from db branch, seems incomplete still. Add some scripts to run the install image. Load some prefs in the new server. Create some conversion utilities for client data. Improved duskz.editor, multi-map support, bugs, layout. --- Makefile | 86 +++++++-- README | 4 +- java.make | 8 +- nbproject/configs/client.properties | 0 nbproject/configs/editor.properties | 2 + nbproject/configs/server-old.properties | 1 + .../classes/duskz/client/DataManager.java | 142 ++++++-------- .../classes/duskz/client/Dusk.java | 20 +- .../classes/duskz/client/GUI.java | 2 +- .../duskz/client/fx/DataManagerFX.java | 147 +++++++------- .../classes/duskz/client/fx/DuskFX.java | 2 +- .../classes/duskz/client/fx/MainFrameFX.java | 74 ++++---- .../internal/scene/control/ListSpinner.css | 50 +++++ .../windows-amd64/bin/run-client.bat | 6 + .../classes/duskz/map/TileMap.java | 87 +++++---- .../classes/duskz/server/DuskEngine.java | 6 +- .../duskz/server/entity/LivingThing.java | 10 +- .../classes/duskz/server/entityz/Game.java | 165 ++++++++-------- .../duskz/server/entityz/GameServer.java | 4 +- .../duskz/server/entityz/ScriptManager.java | 77 ++++++-- src/duskz.server/classes/module-info.java | 1 + src/duskz.server/linux-amd64/bin/run-server | 4 + .../windows-amd64/bin/run-server.bat | 5 + .../classes/duskz/editor/DuskInfoView.java | 17 +- .../classes/duskz/editor/LocationEditor.java | 18 +- .../classes/duskz/editor/TileZ.java | 101 +++++++--- .../classes/duskz/editor/style.css | 4 + .../classes/duskz/tool/Convert.java | 179 +++++++++++++++++- .../classes/duskz/tool/fx/MapView.java | 105 ++++++---- .../classes/duskz/viewer/MapViewer.java | 29 ++- 30 files changed, 884 insertions(+), 472 deletions(-) create mode 100644 nbproject/configs/client.properties create mode 100644 nbproject/configs/editor.properties create mode 100644 nbproject/configs/server-old.properties create mode 100644 src/duskz.client/classes/jfxtras/internal/scene/control/ListSpinner.css create mode 100644 src/duskz.client/windows-amd64/bin/run-client.bat create mode 100755 src/duskz.server/linux-amd64/bin/run-server create mode 100644 src/duskz.server/windows-amd64/bin/run-server.bat create mode 100644 src/duskz.tools/classes/duskz/editor/style.css diff --git a/Makefile b/Makefile index da8e461..4e6e82a 100644 --- a/Makefile +++ b/Makefile @@ -17,26 +17,34 @@ duskz.server_JDEPMOD = duskz.common duskz.editor_JDEPMOD = duskz.common duskz.client duskz.viewer_JDEPMOD = duskz.common duskz.client +define install-bin= +$1_COMMANDS = $(notdir $(wildcard src/$1/$(TARGET)/bin/*)) +bin/$1/$(TARGET)/bin/%: src/$1/$(TARGET)/bin/% + install -D -t $$(@D) $$< +endef +$(foreach mod,$(java_MODULES),$(eval $(call install-bin,$(mod)))) + include java.make -maven_central_JARS = \ - jakarta.xml.bind:jakarta.xml.bind-api:4.0.0 \ - jakarta.activation:jakarta.activation-api:2.1.1 \ - com.sun.xml.bind:jaxb-impl:4.0.1 \ +xmlbind = jakarta.xml.bind:jakarta.xml.bind-api:4.0.0 \ + jakarta.activation:jakarta.activation-api:2.1.1 \ + com.sun.xml.bind:jaxb-impl:4.0.1 \ com.sun.xml.bind:jaxb-core:4.0.2 # two possible javascript engines -maven_central_JARS += \ - org.openjdk.nashorn:nashorn-core:15.4 \ - org.ow2.asm:asm:7.3.1 \ - org.ow2.asm:asm-commons:7.3.1 \ - org.ow2.asm:asm-tree:7.3.1 \ - org.ow2.asm:asm-analysis:7.3.1 \ - org.ow2.asm:asm-util:7.3.1 - -#maven_central_JARS += \ -# org.mozilla:rhino:1.7.14 \ -# org.mozilla:rhino-engine:1.7.14 +# nashorn can't find methods on any objects for some reason +#nashorn += \ +# org.openjdk.nashorn:nashorn-core:15.4 \ +# org.ow2.asm:asm:7.3.1 \ +# org.ow2.asm:asm-commons:7.3.1 \ +# org.ow2.asm:asm-tree:7.3.1 \ +# org.ow2.asm:asm-analysis:7.3.1 \ +# org.ow2.asm:asm-util:7.3.1 + +rhino = org.mozilla:rhino:1.7.14 \ + org.mozilla:rhino-engine:1.7.14 + +maven_central_JARS = $(xmlbind) $(rhino) include maven.make @@ -66,17 +74,57 @@ run-editor: duskz.tools $(if $(JAVAMODPATH),--module-path $(subst $(S),:,$(JAVAMODPATH))) \ -m duskz.tools/duskz.viewer.MapViewer +convert-client: duskz.tools + $(JAVA) \ + $(if $(JAVAMODPATH),--module-path $(subst $(S),:,$(JAVAMODPATH))) \ + -m duskz.tools/duskz.tool.Convert client rc somedusk + + ifeq ($(TARGET),linux-amd64) jlink_MODPATH = $(JAVA_HOME)/jmods:/usr/local/javafx-jmods else jlink_MODPATH = /usr/local/$(TARGET)/jdk/jmods:/usr/local/$(TARGET)/javafx-jmods endif -link: duskz.client duskz.server duskz.common - rm -rf bin/$(TARGET)/image +# need to make rhino modular for jlink to work +bin/org.mozilla.rhino-1.7.14.jar: .lib/rhino-1.7.14.jar .lib/rhino-engine-1.7.14.jar + mkdir -p bin/tmp/org.mozilla.rhino + cd bin/tmp/org.mozilla.rhino && $(JAVA_HOME)/bin/jar xf $(realpath .lib/rhino-engine-1.7.14.jar) + cd bin/tmp/org.mozilla.rhino && $(JAVA_HOME)/bin/jar xf $(realpath .lib/rhino-1.7.14.jar) + jar cfm bin/org.mozilla.rhino.jar bin/tmp/org.mozilla.rhino/META-INF/MANIFEST.MF \ + -C bin/tmp/org.mozilla.rhino META-INF \ + -C bin/tmp/org.mozilla.rhino org + $(JAVA_HOME)/bin/jdeps --generate-module-info bin/gen bin/org.mozilla.rhino.jar + javac -cp rhino.jar -d bin/tmp/org.mozilla.rhino bin/gen/org.mozilla.rhino/module-info.java + jar cfm bin/org.mozilla.rhino-1.7.14.jar~ bin/tmp/org.mozilla.rhino/META-INF/MANIFEST.MF \ + -C bin/tmp/org.mozilla.rhino META-INF \ + -C bin/tmp/org.mozilla.rhino org \ + -C bin/tmp/org.mozilla.rhino module-info.class + mv $@~ $@ + +bin/status/org.mozilla.rhino.engine.classes: .lib/rhino-engine-1.7.14.jar + $(JAVA_HOME)/bin/jdeps --generate-module-info bin/gen/ --module-path .lib $< + mkdir -p bin/modules/org.mozilla.rhino.engine + cd bin/modules/org.mozilla.rhino.engine && $(JAVA_HOME)/bin/jar xf $(realpath $<) + $(JAVAC) -d bin/modules/org.mozilla.rhino.engine \ + --module-path .lib:bin/modules \ + bin/gen/org.mozilla.rhino.engine/module-info.java + +#jarname=$(word 2,$(subst :, ,$1))-$(word 3,$(subst :, ,$1)).jar +define jarname +$(word 2,$(subst :, ,$1))-$(word 3,$(subst :, ,$1)).jar +endef + +# --strip-debug +link: duskz.client duskz.server duskz.common bin/org.mozilla.rhino-1.7.14.jar + rm -rf bin/$(TARGET)/image bin/$(TARGET)/tmp + mkdir -p bin/$(TARGET)/tmp + $(foreach artifact,$(xmlbind),( cd bin/$(TARGET)/tmp && ln -s ../../../.lib/$(call jarname,$(artifact)) ); ) + cd bin/$(TARGET)/tmp ; ln -s ../../org.mozilla.rhino-1.7.14.jar $(JAVA_HOME)/bin/jlink \ - --module-path .lib:bin/$(TARGET)/jmods:$(jlink_MODPATH) \ - --add-modules duskz.client,duskz.server \ + --module-path bin/$(TARGET)/jmods:bin/$(TARGET)/tmp:$(jlink_MODPATH) \ + --add-modules duskz.client,duskz.server,org.mozilla.rhino \ + --bind-services \ --no-man-pages \ --compress 2 \ --output bin/$(TARGET)/image diff --git a/README b/README index 9de326d..92228d9 100644 --- a/README +++ b/README @@ -57,7 +57,9 @@ This is currently in an alpha state. BUIDING ------- -First get the 3rd party libraries from maven: +Copy config.make.in to config.make and configure for your local setup. + +Then get the 3rd party libraries from maven: $ make maven-init diff --git a/java.make b/java.make index 266b0ac..0ecc128 100644 --- a/java.make +++ b/java.make @@ -227,7 +227,7 @@ define module_vars= $1_sdk := $(addprefix $(java_bindir)/,$($1_COMMANDS)) $(addprefix $(java_libdir)/,$($1_LIBRARIES)) $($1_NATIVE_LIBRARIES:%=$(java_libdir)/lib%.so) $1_jmod := $(addprefix $($1_bindir)/,$($1_COMMANDS)) $(addprefix $($1_libdir)/,$($1_LIBRARIES)) $($1_NATIVE_LIBRARIES:%=$($1_libdir)/lib%.so) $1_java :=$($1_JAVA:%=src/$1/classes/%) $($1_JAVA_GENERATED:%=$($1_genjavadir)/%) -$1_resources:= $($1_RESOURCES:%=src/$1/classes/%) $($1_RESOURCES_GENERATED:%=$($1_genjavadir)/%) +$1_resources:= $($1_RESOURCES:%=bin/modules/$1/%) $($1_RESOURCES_GENERATED:%=bin/modules/$1/%) $1_depjava := $($1_API:%=bin/status/$1-%.export) $(patsubst %,bin/status/%.classes, $(filter $($1_JDEPMOD),$(java_MODULES))) ifneq ("$$(strip $$($1_java) $$($1_depjava))", "") @@ -294,9 +294,7 @@ $(java_jardir)/$1.jar: bin/status/$1.depjar @install -d $$(@D) $(JAR) cf $$@ \ $(JARFLAGS) $$($(1)_JARFLAGS) \ - -C bin/modules/$(1) . \ - $(if $($1_RESOURCES),$($1_RESOURCES:%=-C src/$1/classes %)) \ - $(if $($1_RESOURCES_GENERATED),$($1_RESOURCES_GENERATED:%=-C bin/gen/$1/classes %)) + -C bin/modules/$(1) . # Create a jmod $(java_jmoddir)/$1.jmod: bin/status/$1.depmod @@ -322,6 +320,8 @@ $(java_jardir)/$1-sources.zip: bin/status/$1.depjar # resources bin/modules/$1/%: src/$1/classes/% install -vD $$< $$@ +bin/modules/$1/%: $($1_gejavadir)/% + install -vD $$< $$@ # Compile module. bin/status/$1.classes: bin/status/$1.depjava diff --git a/nbproject/configs/client.properties b/nbproject/configs/client.properties new file mode 100644 index 0000000..e69de29 diff --git a/nbproject/configs/editor.properties b/nbproject/configs/editor.properties new file mode 100644 index 0000000..8bbf2f2 --- /dev/null +++ b/nbproject/configs/editor.properties @@ -0,0 +1,2 @@ +main.class=duskz.editor.TileZ +run.jvmargs=-Djavafx.verbose=true -Dprism.verbose=true diff --git a/nbproject/configs/server-old.properties b/nbproject/configs/server-old.properties new file mode 100644 index 0000000..0833fea --- /dev/null +++ b/nbproject/configs/server-old.properties @@ -0,0 +1 @@ +main.class=duskz.server.DuskServer diff --git a/src/duskz.client/classes/duskz/client/DataManager.java b/src/duskz.client/classes/duskz/client/DataManager.java index 3c7343f..65881a1 100644 --- a/src/duskz.client/classes/duskz/client/DataManager.java +++ b/src/duskz.client/classes/duskz/client/DataManager.java @@ -22,46 +22,55 @@ package duskz.client; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.jar.Manifest; -import javafx.geometry.Rectangle2D; -import javafx.scene.image.ImageView; /** - * Utility for loading game objects from jar file - * and managing them - * - * TODO: i couldn't work out how to do generics with the inner class thing - * - * @author notzed + * Utility for loading/managing client game images. + *

*/ public class DataManager { String source; - protected ImageSet[] tilesets; + protected Map sets = new HashMap<>(); public DataManager(String source) { this.source = source; } - public void open() throws IOException { - tilesets = getImageSet("tilesets"); - // TODO: sprites, etc. + public String getSource() { + return source; + } - for (ImageSet is : tilesets) - is.load(); + public ImageSet[] getImageSet(String type) { + return sets.getOrDefault(type, new ImageSet[0]); + } + + public void load() throws IOException { + try (JarInputStream jis = new JarInputStream(new FileInputStream(source + ".jar"))) { + Map> handle = new HashMap<>(); + JarEntry je; + + scanManifest(jis.getManifest(), handle); + + while ((je = jis.getNextJarEntry()) != null) { + Consumer proc = handle.get(je.getName()); + if (proc != null) + proc.accept(jis); + } + } } private int getInt(Attributes a, int index, String name) { try { - return Integer.valueOf(a.getValue(index + "_" + name)); + return Integer.parseInt(a.getValue(name + index)); } catch (NumberFormatException x) { return -1; } @@ -71,55 +80,40 @@ public class DataManager { return new ImageSet(); } - JarInputStream openJar() throws IOException { - return new JarInputStream(new FileInputStream(source)); - } + /** + * Scan manifest for information of interest. + * + * @param man + * @return a predicate that might process a jar entry, it returns true if it was processed. + */ + protected void scanManifest(Manifest man, Map> handle) { + String[] names = new String[]{"tiles", "sprites", "players"}; + + for (String name: names) { + Attributes a = man.getAttributes(name); + int count = Integer.parseInt(a.getValue("count")); + ImageSet[] list = new ImageSet[count]; - public ImageSet[] getImageSet(String setName) throws IOException { - List list; - try (JarInputStream jis = openJar()) { - list = new ArrayList<>(); - Manifest man = jis.getManifest(); - Attributes a = man.getAttributes(setName); - int count = Integer.valueOf(a.getValue("count")); for (int i = 0; i < count; i++) { ImageSet set = createImageSet(); - set.name = a.getValue(i + "_name"); - set.source = a.getValue(i + "_source"); - set.gid = getInt(a, i, "gid"); - set.count = getInt(a, i, "count"); - set.width = getInt(a, i, "width"); - set.height = getInt(a, i, "height"); - - // Load it straight away? - - list.add(set); - } - } - - return list.toArray(new ImageSet[list.size()]); - } - - public InputStream getInputStream(String path) throws IOException { - JarInputStream jis = null; - try { - jis = openJar(); - JarEntry je; - - System.out.println("Looking for: " + path); - - while ((je = jis.getNextJarEntry()) != null) { - System.out.println("je = " + je.getName()); - if (je.getName().equals(path)) - return jis; + set.name = a.getValue("name_" + i); + set.source = a.getValue("source_" + i); + set.gid = getInt(a, i, "gid_"); + set.count = getInt(a, i, "count_"); + set.width = getInt(a, i, "width_"); + set.height = getInt(a, i, "height_"); + + list[i] = set; + handle.put(set.source, jis -> { + try { + set.load(jis); + } catch (IOException ex) { + ex.printStackTrace(); + } + }); } - jis.close(); - throw new FileNotFoundException(path); - } catch (IOException ex) { - if (jis != null) - jis.close(); - throw ex; + sets.put(name, list); } } @@ -135,29 +129,7 @@ public class DataManager { public ImageSet() { } - public void load() throws IOException { + public void load(InputStream is) throws IOException { } - /* - public InputStream getInputStream() throws IOException { - JarInputStream jis = null; - try { - jis = openJar(); - JarEntry je; - - System.out.println("Looking for: " + source); - - while ((je = jis.getNextJarEntry()) != null) { - System.out.println("je = " + je.getName()); - if (je.getName().equals(source)) - return jis; - } - jis.close(); - throw new FileNotFoundException(source); - } catch (IOException ex) { - if (jis != null) - jis.close(); - throw ex; - } - }*/ } } diff --git a/src/duskz.client/classes/duskz/client/Dusk.java b/src/duskz.client/classes/duskz/client/Dusk.java index c63efd7..3f0c303 100644 --- a/src/duskz.client/classes/duskz/client/Dusk.java +++ b/src/duskz.client/classes/duskz/client/Dusk.java @@ -63,14 +63,14 @@ public class Dusk implements Runnable, DuskProtocol { // FIXME: applet will have a different frontend or something //AudioClip audSFX[], audMusic[][]; //AudioClip audMusicPlaying; - String rcLocation; + //String rcLocation; List buyList = new ArrayList<>(); List sellList = new ArrayList<>(); Equipment worn = new Equipment(); private Socket socket; private DataOutputStream outstream; private DataInputStream instream; - int mapSize = 11; + //int mapSize = 11; ClientMap map; boolean intStep, blnMusic = true; @@ -308,18 +308,12 @@ public class Dusk implements Runnable, DuskProtocol { case MSG_INIT_MAP: { ListMessage lm = (ListMessage) dm; + String rc = lm.getString(FIELD_MAP_ASSETLOCATION); + int mapWidth = lm.getInteger(FIELD_MAP_WIDTH); + int mapHeight = lm.getInteger(FIELD_MAP_HEIGHT); - // FIXME: use jar stuff - rcLocation = lm.getString(FIELD_MAP_ASSETLOCATION); - // FIXME: hack - rcLocation = "rc/" + rcLocation; - - frame.setImages(new File(rcLocation + "/images/map.gif").toURI().toString(), 32, - new File(rcLocation + "/images/players.gif").toURI().toString(), 64, - new File(rcLocation + "/images/sprites.gif").toURI().toString(), 64); - - mapSize = lm.getInteger(FIELD_MAP_WIDTH); - map = new ClientMap(mapSize, mapSize); + frame.setImages(rc); + map = new ClientMap(mapWidth, mapHeight); break; } case MSG_UPDATE_MAP: { diff --git a/src/duskz.client/classes/duskz/client/GUI.java b/src/duskz.client/classes/duskz/client/GUI.java index 9bd3490..b4b8ceb 100644 --- a/src/duskz.client/classes/duskz/client/GUI.java +++ b/src/duskz.client/classes/duskz/client/GUI.java @@ -124,7 +124,7 @@ public interface GUI { public void setLookList(List list); // setup/map - public void setImages(String tiles, int tileSize, String players, int playerSize, String sprites, int spriteSize); + public void setImages(String rc); /** * Update the map. diff --git a/src/duskz.client/classes/duskz/client/fx/DataManagerFX.java b/src/duskz.client/classes/duskz/client/fx/DataManagerFX.java index 8281c91..e282c02 100644 --- a/src/duskz.client/classes/duskz/client/fx/DataManagerFX.java +++ b/src/duskz.client/classes/duskz/client/fx/DataManagerFX.java @@ -23,22 +23,25 @@ package duskz.client.fx; import duskz.client.DataManager; import java.io.BufferedReader; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; import javafx.geometry.Rectangle2D; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.scene.image.PixelReader; +import javafx.scene.image.WritableImage; /** * Data manager for JavaFX - loads images into Image nodes and helpers * to create positioned tiles. - * - * @author notzed */ public class DataManagerFX extends DataManager { @@ -57,50 +60,47 @@ public class DataManagerFX extends DataManager { } @Override - public void open() throws IOException { - super.open(); + protected void scanManifest(Manifest man, Map> handle) { + super.scanManifest(man, handle); - try (BufferedReader is = new BufferedReader(new InputStreamReader(getInputStream("tiles/anim")))) { - String line; - PropParser prop = new PropParser(); + handle.put("titles/anim", jis -> { + try (BufferedReader is = new BufferedReader(new InputStreamReader(jis))) { + String line; + PropParser prop = new PropParser(); - while ((line = is.readLine()) != null) { - if (!prop.setInput(line)) - continue; + while ((line = is.readLine()) != null) { + if (!prop.setInput(line)) + continue; - if (!prop.getProperty().startsWith("anim.")) - continue; + if (!prop.getProperty().startsWith("anim.")) + continue; - AnimSetFX anim = new AnimSetFX(prop.getProperty().substring(5)); - List rects = new ArrayList<>(); - while (!prop.eof()) { - int tileid = prop.nextInt(); - int time = 250; + AnimSetFX anim = new AnimSetFX(prop.getProperty().substring(5)); + List rects = new ArrayList<>(); + while (!prop.eof()) { + int tileid = prop.nextInt(); + int time = 250; - if (prop.nextChar(':')) { - time = prop.nextInt(); - } + if (prop.nextChar(':')) { + time = prop.nextInt(); + } - if (anim.root == -1) - anim.root = tileid; - rects.add(createTile(tileid, 0, 0, 64, 64).getViewport()); + if (anim.root == -1) + anim.root = tileid; + rects.add(createTile(tileid, 0, 0, 64, 64).getViewport()); - if (!prop.nextChar(',')) - break; - } - if (anim.root != -1) { - anim.tiles = rects.toArray(new Rectangle2D[rects.size()]); - animset.put(anim.root, anim); + if (!prop.nextChar(',')) + break; + } + if (anim.root != -1) { + anim.tiles = rects.toArray(new Rectangle2D[rects.size()]); + animset.put(anim.root, anim); + } } + } catch (IOException ex) { + ex.printStackTrace(); } - } catch (FileNotFoundException ex) { - } - /* final Rectangle2D[] anims = new Rectangle2D[2]; - anims[0] = data.createTile(305, 0, 0, tileSize, tileSize).getViewport(); - anims[1] = data.createTile(304, 0, 0, tileSize, tileSize).getViewport(); - final List animated = new ArrayList<>(); - */ - + }); } static class PropParser { @@ -161,13 +161,11 @@ public class DataManagerFX extends DataManager { } public void updateTile(ImageView iv, int tileid, int tilewidth, int tileheight) { - for (int i = 0; i < tilesets.length; i++) { - ImageSetFX is = (ImageSetFX) tilesets[i]; + ImageSet[] tiles = sets.get("tiles"); + for (int i = 0; i < tiles.length; i++) { + ImageSetFX is = (ImageSetFX)tiles[i]; if (tileid >= is.gid && tileid < is.gid + is.count) { - tileid -= is.gid; - iv.setImage(is.image); - //iv.setViewport(new Rectangle2D(tileid * is.width, 0, is.width, is.height)); - iv.setViewport(is.getViewport(tileid)); + iv.setImage(is.tiles[tileid - is.gid]); iv.setTranslateY(-(is.height - tileheight)); //iv.relocate(tilex * tilewidth, tiley * tileheight - (is.height - tileheight)); return; @@ -177,7 +175,7 @@ public class DataManagerFX extends DataManager { /** * Create a tile image and align it to the baseline of the map tile. - * + *

* This assumes the tiles are the same width but height may vary * * @param tileid @@ -189,16 +187,39 @@ public class DataManagerFX extends DataManager { */ public ImageView createTile(int tileid, int tilex, int tiley, int tilewidth, int tileheight) { try { - for (int i = 0; i < tilesets.length; i++) { - ImageSetFX is = (ImageSetFX) tilesets[i]; + ImageSet[] tiles = sets.get("tiles"); + for (int i = 0; i < tiles.length; i++) { + ImageSetFX is = (ImageSetFX)tiles[i]; if (tileid >= is.gid && tileid < is.gid + is.count) { - ImageView iv = new ImageView(is.image); - - tileid -= is.gid; - //iv.setViewport(new Rectangle2D(tileid * is.width, 0, is.width, is.height)); - iv.setViewport(is.getViewport(tileid)); + ImageView iv = new ImageView(is.tiles[tileid - is.gid]); iv.relocate(tilex * tilewidth, tiley * tileheight - (is.height - tileheight)); + return iv; + } + } + } catch (Exception x) { + x.printStackTrace(); + } + System.out.println("No such tile: " + tileid); + // Broken image? + return new ImageView(); + } + + public ImageView createSprite(String set, int tileid, int tilex, int tiley, int tilewidth, int tileheight) { + try { + ImageSet[] tiles = sets.get(set); + for (int i = 0; i < tiles.length; i++) { + ImageSetFX is = (ImageSetFX)tiles[i]; + if (tileid >= is.gid && tileid < is.gid + is.count) { + ImageView iv = new ImageView(is.tiles[tileid - is.gid]); + if (is.height != tileheight) { + double scale = (double)tileheight / is.height; + + //iv.relocate(tilex * tilewidth - tilewidth * scale, tiley * tileheight - tileheight * scale); + iv.setScaleX(scale); + iv.setScaleY(scale); + } + iv.relocate(tilex * tilewidth - tilewidth * 0.5, tiley * tileheight - tileheight * 0.5); return iv; } } @@ -225,29 +246,21 @@ public class DataManagerFX extends DataManager { public class ImageSetFX extends ImageSet { Image image; - Rectangle2D tiles[]; + public Image[] tiles; public ImageSetFX() { } - public void load() throws IOException { + @Override + public void load(InputStream is) throws IOException { System.out.println("Load tileset " + name + " gid " + gid + " count " + count); - try (InputStream s = getInputStream(this.source)) { - image = new Image(s); - } + image = new Image(is); - tiles = new Rectangle2D[count]; + tiles = new Image[count]; + PixelReader reader = image.getPixelReader(); for (int i = 0; i < count; i++) { - tiles[i] = new Rectangle2D(i * width, 0, width, height); + tiles[i] = new WritableImage(reader, i * width, 0, width, height); } } - - public Image getImage() { - return image; - } - - public Rectangle2D getViewport(int tileid) { - return tiles[tileid]; - } } } diff --git a/src/duskz.client/classes/duskz/client/fx/DuskFX.java b/src/duskz.client/classes/duskz/client/fx/DuskFX.java index f0450b6..35f71ee 100644 --- a/src/duskz.client/classes/duskz/client/fx/DuskFX.java +++ b/src/duskz.client/classes/duskz/client/fx/DuskFX.java @@ -55,7 +55,7 @@ public class DuskFX extends Application { } }); - stage.getScene().getStylesheets().add(DuskFX.class.getResource("style.css").toExternalForm()); + stage.getScene().getStylesheets().add(DuskFX.class.getResource("style.css").toString()); stage.setTitle("DuskZ JavaFX"); stage.show(); diff --git a/src/duskz.client/classes/duskz/client/fx/MainFrameFX.java b/src/duskz.client/classes/duskz/client/fx/MainFrameFX.java index d991a78..04e7d64 100644 --- a/src/duskz.client/classes/duskz/client/fx/MainFrameFX.java +++ b/src/duskz.client/classes/duskz/client/fx/MainFrameFX.java @@ -34,7 +34,9 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.logging.Level; import java.util.logging.Logger; @@ -850,31 +852,22 @@ public class MainFrameFX extends StackPane implements GUI { }); } DataManagerFX data; - //Image tileImage; - int tileSize; + int tileSize = 32; Image playerImage; int playerSize; Image spriteImage; int spriteSize; @Override - public void setImages(String tiles, int tileSize, String players, int playerSize, String sprites, int spriteSize) { + public void setImages(String rc) { try { - System.out.println("set tile image"); - // FIXME: put sprites into data manager - data = new DataManagerFX("tileset.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; + data = new DataManagerFX(rc); + data.load(); } catch (IOException ex) { Logger.getLogger(MainFrameFX.class.getName()).log(Level.SEVERE, null, ex); } } - TileAnimator animator; + HashMap animators = new HashMap<>(); @Override public void updateMap(ClientMap map) { @@ -895,11 +888,8 @@ public class MainFrameFX extends StackPane implements GUI { final ArrayList upper = new ArrayList<>(); int levelCount = map.getLevelCount(); - // Animated tiles hack test - final Rectangle2D[] anims = new Rectangle2D[2]; - anims[0] = data.createTile(305, 0, 0, tileSize, tileSize).getViewport(); - anims[1] = data.createTile(304, 0, 0, tileSize, tileSize).getViewport(); - final List animated = new ArrayList<>(); + // Animated tiles stuff + final HashMap> animated = new HashMap<>(); // Build map for (int l = 0; l < levelCount; l++) { @@ -911,8 +901,14 @@ public class MainFrameFX extends StackPane implements GUI { ImageView iv = data.createTile(tileid, x, y, tileSize, tileSize); children.add(iv); - if (tileid == 305) - animated.add(iv); + if (data.isAnimRoot(tileid)) { + List list = animated.get(tileid); + if (list == null) { + list = new ArrayList<>(); + animated.put(tileid, list); + } + list.add(iv); + } } } @@ -940,13 +936,20 @@ public class MainFrameFX extends StackPane implements GUI { graphics.getChildren().setAll(children); graphics.getChildren().addAll(upper); - System.out.println("animated node count = " + animated.size()); - if (animator == null) { - animator = new TileAnimator(animated, Duration.seconds(0.25), anims); - animator.setCycleCount(Animation.INDEFINITE); - animator.play(); - } else - animator.setNodes(animated); + for (Map.Entry> e: animated.entrySet()) { + int root = e.getKey(); + TileAnimator animator = animators.get(root); + DataManagerFX.AnimSetFX set = data.getAnimSet(root); + if (animator == null) { + animator = new TileAnimator(e.getValue(), Duration.seconds(0.25), set.tiles); + animators.put(root, animator); + animator.setCycleCount(Animation.INDEFINITE); + animator.play(); + } else { + animator.setNodes(e.getValue()); + } + System.out.printf("Set anim root %d\n", root); + } } }); } @@ -959,22 +962,11 @@ public class MainFrameFX extends StackPane implements GUI { // TODO: just make it an entity node if (e.intStep == -1) { - // Hack: sprites are 64x64 - ImageView iv = new ImageView(spriteImage); - iv.setViewport(new Rectangle2D(e.intImage * spriteSize, 0, - spriteSize, spriteSize)); - iv.relocate((x * tileSize) - tileSize / 2, (y * tileSize) - tileSize / 2); - iv.setScaleX(0.5); - iv.setScaleY(0.5); + ImageView iv = data.createSprite("sprites", e.intImage, e.locx - offx, e.locy - offy, tileSize, tileSize); children.add(iv); } else { - ImageView iv = new ImageView(playerImage); - iv.setViewport(new Rectangle2D((e.intImage * 8 + e.intStep) * spriteSize, 0, - spriteSize, spriteSize)); - iv.relocate((x * tileSize) + tileSize / 2 - spriteSize / 2, (y * tileSize) - spriteSize / 2); - iv.setScaleX(1); - iv.setScaleY(1); + ImageView iv = data.createSprite("players", e.intImage * 8 + e.intStep, e.locx - offx, e.locy - offy, tileSize, tileSize); children.add(iv); } // FIXME: intnum not used anymore diff --git a/src/duskz.client/classes/jfxtras/internal/scene/control/ListSpinner.css b/src/duskz.client/classes/jfxtras/internal/scene/control/ListSpinner.css new file mode 100644 index 0000000..52fa048 --- /dev/null +++ b/src/duskz.client/classes/jfxtras/internal/scene/control/ListSpinner.css @@ -0,0 +1,50 @@ +/* basic settings */ +.ListSpinner { + -fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color; + -fx-background-insets: 0 0 -1 0, 0, 1, 2; + -fx-background-radius: 5, 5, 4, 3; + -fx-padding: 0.266667em 0.233333em 0.25em 0.233333em; + -fx-text-fill: -fx-text-base-color; +} + +.ListSpinner:hover { + -fx-color: -fx-hover-base; +} + +.ListSpinner:focused { + -fx-color: -fx-base; + -fx-background-color: -fx-focus-color, -fx-outer-border, -fx-inner-border, -fx-body-color; + -fx-background-insets: -1.4, 0, 1, 2; + -fx-background-radius: 6.4, 5, 4, 3; +} + +.ListSpinner .valuePane { + -fx-padding: 0.0em 0.2em 0.0em 0.2em; +} + +.ListSpinner .left-arrow { + -fx-shape: "M4,-4 L0,0 L4,4 Z"; + -fx-scale-shape: false; + -fx-padding: 8; +} +.ListSpinner .right-arrow { + -fx-shape: "M0,-4 L4,0 L0,4 Z"; + -fx-scale-shape: false; + -fx-padding: 8; +} +.ListSpinner .down-arrow { + -fx-shape: "M-4,-2 L0,2 L4,-2 Z"; + -fx-scale-shape: false; + -fx-padding: 8; +} +.ListSpinner .up-arrow { + -fx-shape: "M4,2 L-4,2 L0,-2 Z"; + -fx-scale-shape: false; + -fx-padding: 8; +} +.ListSpinner .idle { + -fx-background-color: -fx-mark-color; +} +.ListSpinner .clicked { + -fx-background-color: -fx-focus-color; +} diff --git a/src/duskz.client/windows-amd64/bin/run-client.bat b/src/duskz.client/windows-amd64/bin/run-client.bat new file mode 100644 index 0000000..ccc4cca --- /dev/null +++ b/src/duskz.client/windows-amd64/bin/run-client.bat @@ -0,0 +1,6 @@ +REM run-client +@echo off +set JAVA_HOME=%~dp0\.. +rem stops cmd window staying visible +rem start /min "dusk client" "%JAVA_HOME%\bin\java" -m duskz.client/duskz.client.fx.DuskFX +"%JAVA_HOME%\bin\java" -m duskz.client/duskz.client.fx.DuskFX diff --git a/src/duskz.common/classes/duskz/map/TileMap.java b/src/duskz.common/classes/duskz/map/TileMap.java index de35e0b..e851b3c 100644 --- a/src/duskz.common/classes/duskz/map/TileMap.java +++ b/src/duskz.common/classes/duskz/map/TileMap.java @@ -45,7 +45,7 @@ import java.util.zip.GZIPInputStream; /** * Low level map management and helpers. - * + *

* Some of the helpers provide higher level functionality like path finding. * * @author notzed @@ -88,7 +88,7 @@ public class TileMap implements Iterable implements Iterable implements Iterable= 0 && tx < width - && ty >= 0 && ty < height; + && 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) { + && ty >= 0 && ty < height) { return tiles[tx + ty * width]; } else return 0; @@ -196,7 +197,7 @@ public class TileMap implements Iterable * TODO: sort something out with the alias stuff and loadLayered() * * @param is @@ -217,7 +218,7 @@ public class TileMap implements Iterable implements Iterable implements Iterable implements Iterable implements Iterable= 0 && x < cols - && y >= 0 && y < rows; + && y >= 0 && y < rows; } public boolean inside(int layer, int x, int y) { return x >= 0 && x < cols - && y >= 0 && y < rows; + && y >= 0 && y < rows; } /** @@ -508,7 +509,7 @@ public class TileMap implements Iterable implements Iterable implements Iterable implements Iterable * TODO: it should probably use Bresenhams line algorithm */ private class LookIterator implements Iterator { @@ -897,7 +898,6 @@ public class TileMap implements Iterable implements Iterable implements Iterable * Implemented using A* algorithm, so can handle obstructions. - * + *

* TODO: Limit the search space. */ private class MoveIterator implements Iterator { @@ -1011,13 +1011,12 @@ public class TileMap implements Iterable path = findPath(); System.out.printf("Finding path from %d,%d to %d,%d: ", sx, sy, ex, ey); if (path != null) { - for (MoveInfo mi : path) { + for (MoveInfo mi: path) { System.out.print(" "); System.out.print(mi.direction); } @@ -1034,7 +1033,7 @@ public class TileMap implements Iterable constructPath(List list, MoveInfo n) { @@ -1098,7 +1097,7 @@ public class TileMap implements Iterable * Handles game setup, prefs, loading/restoring state, and the main * game clock. * @@ -149,7 +152,14 @@ public class Game { props = new ThingTable<>(new File(root, "props")); // Load preferences - // TODO: load preferences + // TODO: load more preferences + Properties prefs = new Properties(); + try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(confDir, "prefs")))) { + prefs.load(bis); + } catch (FileNotFoundException ex) { + log.printf(ex, "Preferences not found: %s", new File(confDir, "prefs")); + } + rcName = prefs.getProperty("rcname", "somedusk"); // Load all races (move to 'racelist' class?) { @@ -157,7 +167,7 @@ public class Game { if (!path.isDirectory()) throw new FileNotFoundException("Unable to find races"); - for (File file : path.listFiles()) { + for (File file: path.listFiles()) { try { Race race = Race.loadRace(file); races.put(race.name, race); @@ -172,7 +182,7 @@ public class Game { File path = new File(root, "defMaps"); if (!path.isDirectory()) throw new FileNotFoundException("Unable to find maps"); - for (File file : path.listFiles()) { + for (File file: path.listFiles()) { if (file.getName().endsWith(".alias")) continue; try { @@ -190,20 +200,20 @@ public class Game { { File path = new File(root, "tileScriptMap"); try (PropertyLoader pl = new PropertyLoader(path)) { - for (PropertyLoader.PropertyEntry pe : pl) { + for (PropertyLoader.PropertyEntry pe: pl) { String[] line = pe.name.split("\\."); Integer id = Integer.valueOf(line[0]); switch (line[1]) { - case "visible": - tileVisible.put(id, pe.value); - break; - case "able": - tileAble.put(id, pe.value); - break; - case "action": - tileAction.put(id, pe.value); - break; + case "visible": + tileVisible.put(id, pe.value); + break; + case "able": + tileAble.put(id, pe.value); + break; + case "action": + tileAction.put(id, pe.value); + break; } } } @@ -224,7 +234,7 @@ public class Game { File path = new File(root, "factions"); if (!path.isDirectory()) throw new FileNotFoundException("Unable to find factions"); - for (File file : path.listFiles()) { + for (File file: path.listFiles()) { try { Faction f = new Faction(file.getName(), this); f.load(); @@ -242,7 +252,7 @@ public class Game { File path = new File(root, "defMobs"); if (!path.isDirectory()) throw new FileNotFoundException("Unable to find mobs"); - for (File file : path.listFiles()) { + for (File file: path.listFiles()) { try { Mobile mob = new Mobile(this); mob.load(file); @@ -254,7 +264,6 @@ public class Game { } } - // Load all active objects // FIXME: has to copy to various indices mobs.restoreState(this, new File(root, "defMobs")); @@ -263,15 +272,15 @@ public class Game { props.restoreState(this); // HACK: just copy to indices now - for (Mobile m : mobs.values()) { + for (Mobile m: mobs.values()) { System.out.println("add mob " + m.name + " on " + m.map.name); addThing(m); } - for (Sign s : signs.values()) { + for (Sign s: signs.values()) { System.out.println("add sign: " + s.name + " at " + s.x + ", " + s.y + " on map " + s.map.name); addThing(s); } - for (Shop s : gameShops.values()) { + for (Shop s: gameShops.values()) { System.out.println("add shop: " + s.name + " at " + s.x + ", " + s.y + " on map " + s.map.name); addThing(s); } @@ -318,7 +327,7 @@ public class Game { Thing.ThingResolver resolver = new Thing.EmptyResolver(); try (BufferedReader in = new BufferedReader(new FileReader(new File(root, "defItems/" + name.toLowerCase())))) { - return (Holdable) Thing.restoreState(this, in, resolver); + return (Holdable)Thing.restoreState(this, in, resolver); } catch (IOException ex) { log.printf(ex, "Loading item: %s", name); } @@ -333,8 +342,8 @@ public class Game { */ public boolean isPreference(String name) { switch (name) { - case PREF_AI: - return true; + case PREF_AI: + return true; } // FIXME: implement properly return true; @@ -350,7 +359,7 @@ public class Game { */ public void globalChat(Player from, String clan, String msg) { //log.printMessage(Log.ALWAYS, msg); - for (Player player : players.values()) { + for (Player player: players.values()) { player.chatMessage(from, clan, msg); } } @@ -377,17 +386,17 @@ public class Game { assert (things.containsKey(thing.ID)); switch (thing.getType()) { - case Thing.TYPE_PLAYER: - players.remove(((Player) thing).name); - actives.remove(thing.ID); - break; - case Thing.TYPE_MOBILE: - mobs.remove((Mobile) thing); - actives.remove(thing.ID); - break; - case Thing.TYPE_PET: - actives.remove(thing.ID); - break; + case Thing.TYPE_PLAYER: + players.remove(((Player)thing).name); + actives.remove(thing.ID); + break; + case Thing.TYPE_MOBILE: + mobs.remove((Mobile)thing); + actives.remove(thing.ID); + break; + case Thing.TYPE_PET: + actives.remove(thing.ID); + break; } thing.map.removeEntity(thing); @@ -399,20 +408,20 @@ public class Game { things.put(t.ID, t); switch (t.getType()) { - case Thing.TYPE_PLAYER: { - Player player = (Player) t; - players.put(player.name, player); - actives.put(player.ID, player); - break; - } - case Thing.TYPE_MOBILE: - mobs.add((Mobile) t); - actives.put(t.ID, (Active) t); - // Mobs are not addded to the map directly, respawn does it - return; - case Thing.TYPE_PET: - actives.put(t.ID, (Active) t); - break; + case Thing.TYPE_PLAYER: { + Player player = (Player)t; + players.put(player.name, player); + actives.put(player.ID, player); + break; + } + case Thing.TYPE_MOBILE: + mobs.add((Mobile)t); + actives.put(t.ID, (Active)t); + // Mobs are not addded to the map directly, respawn does it + return; + case Thing.TYPE_PET: + actives.put(t.ID, (Active)t); + break; } t.map.addEntity(t); } @@ -510,8 +519,8 @@ public class Game { if (name != null) { runScript(tileActionDir, name, - "game", this, - "trigger", trigger); + "game", this, + "trigger", trigger); } } @@ -520,8 +529,8 @@ public class Game { if (name != null) { return runScriptBoolean(false, tileVisibleDir, name, - "game", this, - "trigger", trigger); + "game", this, + "trigger", trigger); } return false; } @@ -530,11 +539,10 @@ public class Game { String name = tileAble.get(tileid); //System.out.printf("onTileTable tid=%d script=%s\n", tileid, name); - if (name != null) { return runScriptBoolean(false, tileAbleDir, name, - "game", this, - "trigger", trigger); + "game", this, + "trigger", trigger); } return false; } @@ -545,7 +553,7 @@ public class Game { TileMap map = trigger.map; Location l = map.locationForAlias(alias); if (l == null) { - for (TileMap scan : maps.values()) { + for (TileMap scan: maps.values()) { l = scan.locationForAlias(alias); if (l != null) { map = scan; @@ -555,7 +563,7 @@ public class Game { } if (l != null) { System.out.printf("direct jump to '%s' map %s %d,%d\n", - alias, map.name, l.x, l.y); + alias, map.name, l.x, l.y); trigger.jumpTo(map, l.x, l.y); return; } else { @@ -564,8 +572,8 @@ public class Game { } runScript(locationActionDir, trigger.map.locationActionScript(x, y), - "game", this, - "trigger", trigger); + "game", this, + "trigger", trigger); } private boolean haveMoveAble(Active trigger, int x, int y) { @@ -574,8 +582,8 @@ public class Game { private boolean onMoveAble(Active trigger, int x, int y) { return runScriptBoolean(false, locationAbleDir, trigger.map.locationAbleScript(x, y), - "game", this, - "trigger", trigger); + "game", this, + "trigger", trigger); } private boolean haveMoveVisible(Active trigger, int x, int y) { @@ -585,8 +593,8 @@ public class Game { private boolean onMoveVisible(Active trigger, int x, int y) { return runScriptBoolean(false, locationVisibleDir, trigger.map.locationVisibleScript(x, y), - "game", this, - "trigger", trigger); + "game", this, + "trigger", trigger); } /** @@ -656,9 +664,9 @@ public class Game { */ public void onItem(Active owner, Holdable item, String what) { runScript(onScriptDir, item.name + "." + what, - "game", this, - "owner", owner, - "item", item); + "game", this, + "owner", owner, + "item", item); } public boolean haveOnCondition(Holdable trigger, String what) { @@ -674,9 +682,9 @@ public class Game { */ public void onCondition(Active owner, Condition cond, String what) { runScript(onConditionDir, cond.name + "." + what, - "game", this, - "owner", owner, - "condition", cond); + "game", this, + "owner", owner, + "condition", cond); } private int tick; @@ -686,7 +694,7 @@ public class Game { /** * Main game loop. - * + *

* 1. all actives are moved active.moveTick() * 2. run per-tick activities * 3. run player updates @@ -696,16 +704,16 @@ public class Game { void gameTick(int tick) { this.tick = tick; // TODO: the order of this might need tweaking - for (Active a : actives.values()) { + for (Active a: actives.values()) { a.moveTick(); } - for (Active a : actives.values()) { + for (Active a: actives.values()) { a.tick(tick); } //if (tick % 10 == 0) { if (tick % battleRate == 0) { ArrayList done = new ArrayList<>(); - for (Battle b : battles) { + for (Battle b: battles) { if (b.isFighting()) { b.run(); } else { @@ -715,7 +723,7 @@ public class Game { battles.removeAll(done); } - for (Active a : actives.values()) { + for (Active a: actives.values()) { a.visibilityTick(tick); } } @@ -736,7 +744,6 @@ public class Game { boolean checkPassword(String name, String pass, String address) throws TooManyTriesException, BlockedIPException { // TODO: handle ip blocked checking here - Player p = new Player(this, null); try { p.load(new File(root, "players/" + name.toLowerCase())); @@ -792,7 +799,7 @@ public class Game { Pattern valid = Pattern.compile("^[A-Za-z]+$"); if (reserved.matcher(lcplayer).matches() - || !valid.matcher(player).matches()) { + || !valid.matcher(player).matches()) { return false; } @@ -855,7 +862,7 @@ public class Game { public List getRaceNames() { ArrayList l = new ArrayList<>(races.size()); - for (Race r : races.values()) { + for (Race r: races.values()) { l.add(r.name); } return l; diff --git a/src/duskz.server/classes/duskz/server/entityz/GameServer.java b/src/duskz.server/classes/duskz/server/entityz/GameServer.java index 5368059..4ac6385 100644 --- a/src/duskz.server/classes/duskz/server/entityz/GameServer.java +++ b/src/duskz.server/classes/duskz/server/entityz/GameServer.java @@ -45,7 +45,7 @@ import java.util.logging.Logger; public class GameServer { // ms per tick: TODO: move into game prefs - int tickRate = 250; + int tickRate = 100; boolean cancelled = false; ServerSocket serverSocket; Socket socket; @@ -61,7 +61,7 @@ public class GameServer { System.err.println(); System.err.println(why); } - + /** * Creates a new DuskServer object; */ diff --git a/src/duskz.server/classes/duskz/server/entityz/ScriptManager.java b/src/duskz.server/classes/duskz/server/entityz/ScriptManager.java index ab9c5a9..88bed64 100644 --- a/src/duskz.server/classes/duskz/server/entityz/ScriptManager.java +++ b/src/duskz.server/classes/duskz/server/entityz/ScriptManager.java @@ -45,6 +45,7 @@ import java.util.concurrent.ThreadFactory; import java.util.logging.Level; import java.util.logging.Logger; import javax.script.Bindings; +import javax.script.Invocable; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; @@ -52,14 +53,14 @@ import javax.script.SimpleScriptContext; /** * Manages the (javascript) engine - * + *

* Doing this securely is complicated, so is likely to be buggy and not really * secure ... - * + *

* I found I had to create the script engine itself from the same doPrivileged() * invocation or it simply broke the sanboxing. Hence all script execution is * performed from a pool of threads created from the same sandbox. - * + *

* Another thread monitors the pool checking for out of control scripts (i.e. * they take too long to run). * @@ -78,15 +79,14 @@ public class ScriptManager { public ScriptManager() { Permissions perms = new Permissions(); - + // FIXME: fix security manager for the actual paths used - //perms.add(new AllPermission()); perms.add(new FilePermission("scripts/*", "read,write")); // perms.add(new NetPermission("*")); //perms.add(new RuntimePermission("accessDeclaredMembers")); // Cast to Certificate[] required because of ambiguity: - ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms); + ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[])null), perms); ac = new AccessControlContext(new ProtectionDomain[]{domain}); } @@ -109,7 +109,6 @@ public class ScriptManager { }); // TOOD: anything else I want to do here? A management/monitoring thread? - return null; } }, ac); @@ -138,9 +137,8 @@ public class ScriptManager { // Well it mozilla code after-all ... // So i'm forced to use stop with all its apparent dangers. - long now = System.currentTimeMillis(); - for (Entry e : active.entrySet()) { + for (Entry e: active.entrySet()) { if ((now - e.getValue()) > 1000) { System.out.println("Job taking too long, interrupting it!"); //e.getKey().interrupt(); @@ -177,14 +175,14 @@ public class ScriptManager { public ScriptData(String script, Object... args) { for (int i = 0; i < args.length; i += 2) { - this.args.put((String) args[i], args[i + 1]); + this.args.put((String)args[i], args[i + 1]); } this.script = script; } public ScriptData(File scriptFile, Object... args) throws FileNotFoundException, ClassCastException { for (int i = 0; i < args.length; i += 2) { - this.args.put((String) args[i], args[i + 1]); + this.args.put((String)args[i], args[i + 1]); } this.scriptReader = new FileReader(scriptFile); } @@ -203,11 +201,17 @@ public class ScriptManager { b.clear(); b.putAll(args); + System.out.println("invoke ["); + for (String s: b.keySet()) { + System.out.printf("arg %s: %s\n", s, b.get(s)); + } + System.out.println("]\n"); + startJob(Thread.currentThread()); if (scriptReader != null) - res = (T) engine.eval(scriptReader, b); + res = (T)engine.eval(scriptReader, b); else - res = (T) engine.eval(script, b); + res = (T)engine.eval(script, b); // lastStart = -1; b.clear(); } finally { @@ -219,7 +223,38 @@ public class ScriptManager { } }; + public static class Bob { + public String bob() { + System.out.println("bob called\n"); + return "3"; + } + } public static void main(String[] args) { + + if (true) { + try { + ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript"); + System.out.println(engine); + engine.eval(""" + function foo(trigger) { + print(trigger.hashCode()); + print(typeof trigger); + print(typeof trigger.bob); + print(typeof trigger['bob']); + print(trigger.bob()); + } + """); + Invocable invocable = (Invocable)engine; + + Bob b = new Bob(); + Object x = invocable.invokeFunction("foo", b); + System.out.println(x); + } catch (Exception ex) { + ex.printStackTrace(System.out); + } + return; + } + // Lets see if it the security shit works ScriptManager sm = new ScriptManager(); @@ -242,9 +277,9 @@ public class ScriptManager { try { String s = "var out = new java.io.FileOutputStream('hack-thread.txt');" - + " out.write(65);" - + "out.close();" - + " println('wrote hack.txt ok');"; + + " out.write(65);" + + "out.close();" + + " println('wrote hack.txt ok');"; f = sm.runScript(s); System.out.println("result = " + f.get()); @@ -259,8 +294,8 @@ public class ScriptManager { } try { String s = "var out = new java.io.FileInputStream('hack.script');" - + "out.close();" - + " println('read hack.script ok');"; + + "out.close();" + + " println('read hack.script ok');"; f = sm.runScript(s); System.out.println("result = " + f.get()); @@ -283,9 +318,9 @@ public class ScriptManager { } try { String s = "var out = new java.io.FileOutputStream('scripts/newscript');" - + " out.write(65);" - + "out.close();" - + " println('wrote scripts/newscript ok');"; + + " out.write(65);" + + "out.close();" + + " println('wrote scripts/newscript ok');"; f = sm.runScript(s); System.out.println("result = " + f.get()); diff --git a/src/duskz.server/classes/module-info.java b/src/duskz.server/classes/module-info.java index 979f666..7b8065c 100644 --- a/src/duskz.server/classes/module-info.java +++ b/src/duskz.server/classes/module-info.java @@ -23,4 +23,5 @@ module duskz.server { requires java.desktop; requires java.logging; + exports duskz.server.entityz to org.mozilla.rhino, org.openjdk.nashorn; } diff --git a/src/duskz.server/linux-amd64/bin/run-server b/src/duskz.server/linux-amd64/bin/run-server new file mode 100755 index 0000000..3ee3dfd --- /dev/null +++ b/src/duskz.server/linux-amd64/bin/run-server @@ -0,0 +1,4 @@ +#!/bin/bash + +export JAVA_HOME=$(dirname $(readlink -f $0))/.. +exec ${JAVA_HOME}/bin/java -m duskz.server/duskz.server.entityz.GameServer $@ diff --git a/src/duskz.server/windows-amd64/bin/run-server.bat b/src/duskz.server/windows-amd64/bin/run-server.bat new file mode 100644 index 0000000..5e1bb7c --- /dev/null +++ b/src/duskz.server/windows-amd64/bin/run-server.bat @@ -0,0 +1,5 @@ +REM run-server game-dir +@echo off +set JAVA_HOME=%~dp0\.. +rem stops cmd window staying visible +start /min "server" "%JAVA_HOME%\bin\java" -m duskz.server/duskz.server.entityz.GameServer %* diff --git a/src/duskz.tools/classes/duskz/editor/DuskInfoView.java b/src/duskz.tools/classes/duskz/editor/DuskInfoView.java index b99ac98..286b372 100644 --- a/src/duskz.tools/classes/duskz/editor/DuskInfoView.java +++ b/src/duskz.tools/classes/duskz/editor/DuskInfoView.java @@ -35,7 +35,7 @@ import javafx.scene.layout.VBox; */ public class DuskInfoView extends BorderPane { - String oldmap = "/home/notzed/src/DuskRPG/DuskFiles/Dusk2.7.3"; + String oldmap = "game-2.7.3"; TextArea action; TextArea able; @@ -44,13 +44,18 @@ public class DuskInfoView extends BorderPane { action = new TextArea(); able = new TextArea(); - + action.setEditable(false); able.setEditable(false); - vbox.getChildren().addAll( - new TitledPane("defMoveActions", action), - new TitledPane("defCanMoveScripts", able)); + action.setPrefColumnCount(60); + able.setPrefColumnCount(60); + + TitledPane move = new TitledPane("defMoveActions", action); + TitledPane canMove = new TitledPane("defCanMoveScripts", able); + vbox.getChildren().addAll(move, canMove); + move.setAnimated(false); + canMove.setAnimated(false); setCenter(vbox); } @@ -60,7 +65,7 @@ public class DuskInfoView extends BorderPane { try { byte[] data = Files.readAllBytes(path.toPath()); String string = new String(data, Charset.defaultCharset()).trim(); - + if (!string.equals("")) text.setText(string); else diff --git a/src/duskz.tools/classes/duskz/editor/LocationEditor.java b/src/duskz.tools/classes/duskz/editor/LocationEditor.java index 36b9e1b..7315f66 100644 --- a/src/duskz.tools/classes/duskz/editor/LocationEditor.java +++ b/src/duskz.tools/classes/duskz/editor/LocationEditor.java @@ -45,7 +45,7 @@ import javafx.scene.layout.GridPane; */ public class LocationEditor extends BorderPane implements ChangeListener { - String game = "/home/notzed/dusk/game"; + String game = "game"; int tx, ty; TileMap map; TextField alias; @@ -72,10 +72,15 @@ public class LocationEditor extends BorderPane implements ChangeListener actionScript = new TextArea(); visibleScript = new TextArea(); + ableScript.setPrefColumnCount(60); + actionScript.setPrefColumnCount(60); + visibleScript.setPrefColumnCount(60); + Button aliasb, gotob, ableb, visibleb, actionb; int r = 0; TextField location; + TitledPane tp; main.add(new Button("Location"), 0, r); main.add(location = new TextField(), 1, r++); main.add(aliasb = new Button("Alias"), 0, r); @@ -84,13 +89,16 @@ public class LocationEditor extends BorderPane implements ChangeListener main.add(jumpto, 1, r++); main.add(actionb = new Button("Action"), 0, r); main.add(action, 1, r++); - main.add(new TitledPane("Action Script", actionScript), 0, r++, 2, 1); + main.add(tp = new TitledPane("Action Script", actionScript), 0, r++, 2, 1); + tp.setAnimated(false); main.add(ableb = new Button("Able"), 0, r); main.add(able, 1, r++); - main.add(new TitledPane("Able Script", ableScript), 0, r++, 2, 1); + main.add(tp = new TitledPane("Able Script", ableScript), 0, r++, 2, 1); + tp.setAnimated(false); main.add(visibleb = new Button("Visible"), 0, r); main.add(visible, 1, r++); - main.add(new TitledPane("Visible Script", visibleScript), 0, r++, 2, 1); + main.add(tp = new TitledPane("Visible Script", visibleScript), 0, r++, 2, 1); + tp.setAnimated(false); location.textProperty().bind(tileX.asString().concat(", ").concat(tileY.asString())); @@ -155,7 +163,7 @@ public class LocationEditor extends BorderPane implements ChangeListener try { TextEditor te = new TextEditor(); - te.setPath(Paths.get("/home/notzed/dusk/game", type, name)); + te.setPath(Paths.get(game, type, name)); te.show(); } catch (IOException ex) { Logger.getLogger(LocationEditor.class.getName()).log(Level.SEVERE, null, ex); diff --git a/src/duskz.tools/classes/duskz/editor/TileZ.java b/src/duskz.tools/classes/duskz/editor/TileZ.java index 5373236..573802e 100644 --- a/src/duskz.tools/classes/duskz/editor/TileZ.java +++ b/src/duskz.tools/classes/duskz/editor/TileZ.java @@ -18,15 +18,25 @@ package duskz.editor; import duskz.client.fx.DataManagerFX; +import duskz.map.TileMap; import duskz.tool.fx.MapSelectionModel; import duskz.tool.fx.MapView; +import java.io.DataInputStream; +import java.io.FileInputStream; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.zip.GZIPInputStream; import javafx.application.Application; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.scene.Scene; +import javafx.scene.control.ChoiceBox; +import javafx.scene.control.ToolBar; import javafx.scene.layout.BorderPane; import javafx.scene.layout.VBox; import javafx.stage.Stage; @@ -42,49 +52,57 @@ public class TileZ extends Application { LocationEditor locationEditor; DuskInfoView oldInfo; DataManagerFX data; + Path game = Path.of("game"); + String rcName = "nowhere"; @Override - public void start(Stage stage) { + public void start(Stage stage) throws IOException { BorderPane root = new BorderPane(); VBox left = new VBox(); + ToolBar toolbar = new ToolBar(); left.getChildren().addAll( - locationEditor = new LocationEditor(), - oldInfo = new DuskInfoView()); + locationEditor = new LocationEditor(), + oldInfo = new DuskInfoView()); + ChoiceBox maps = new ChoiceBox<>(findMaps(game)); + + toolbar.getItems().add(maps); + + root.setTop(toolbar); root.setCenter(mapView = new MapView()); root.setLeft(left); - Scene scene = new Scene(root, 768, 512); + Scene scene = new Scene(root, 1280, 768); + scene.getStylesheets().add(TileZ.class.getResource("style.css").toString()); stage.setTitle("TileZ"); stage.setScene(scene); stage.show(); - String datapath = "/home/notzed/house.jar"; - String mappath = "/home/notzed/dusk/game/defMaps/dusk"; + maps.getSelectionModel().selectedItemProperty().addListener((ObservableValue o, Path ov, Path nv) -> { + loadMap(nv); + }); - try { - data = new DataManagerFX(datapath); - data.open(); - mapView.loadMap(data, mappath); - - locationEditor.setMap(mapView.getMap()); - - mapView.getSelectionModel().boundsProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue ov, MapSelectionModel.Bounds t, MapSelectionModel.Bounds t1) { - if (t1 != null) { - locationEditor.setTileX(t1.left); - locationEditor.setTileY(t1.top); - oldInfo.setLocation(t1.left, t1.top); - } else { - locationEditor.setTileX(-1); - locationEditor.setTileY(-1); - } + mapView.getSelectionModel().boundsProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue ov, MapSelectionModel.Bounds t, MapSelectionModel.Bounds t1) { + if (t1 != null) { + locationEditor.setTileX(t1.left); + locationEditor.setTileY(t1.top); + oldInfo.setLocation(t1.left, t1.top); + } else { + locationEditor.setTileX(-1); + locationEditor.setTileY(-1); } - }); + } + }); + + try { + data = new DataManagerFX(rcName); + data.load(); + maps.getSelectionModel().select(0); } catch (IOException ex) { Logger.getLogger(TileZ.class.getName()).log(Level.SEVERE, null, ex); } @@ -96,6 +114,39 @@ public class TileZ extends Application { TZ.shutdown(); } + void loadMap(Path map) { + try { + if (map != null) { + mapView.loadExternalMap(data, map.toString()); + locationEditor.setMap(mapView.getMap()); + } else { + TileMap tm = new TileMap("empty", 0, 0); + mapView.setMap(tm); + locationEditor.setMap(tm); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + ObservableList findMaps(Path game) throws IOException { + return FXCollections.observableArrayList( + Files.list(game.resolve("defMaps")) + .filter(p -> { + // TODO: check if gzip, etc. + try (DataInputStream dis = new DataInputStream(new GZIPInputStream(new FileInputStream(p.toFile())))) { + int magic = dis.readInt(); + int version = dis.readInt(); + System.out.printf("magic: %08x\n", magic); + + return magic == TileMap.MAGIC_LAYERED; + } catch (IOException x) { + return false; + } + }) + .toList()); + } + /** * The main() method is ignored in correctly deployed JavaFX * application. main() serves only as fallback in case the diff --git a/src/duskz.tools/classes/duskz/editor/style.css b/src/duskz.tools/classes/duskz/editor/style.css new file mode 100644 index 0000000..d50803f --- /dev/null +++ b/src/duskz.tools/classes/duskz/editor/style.css @@ -0,0 +1,4 @@ + +.text-area { + -fx-font: 10pt monospace; +} \ No newline at end of file diff --git a/src/duskz.tools/classes/duskz/tool/Convert.java b/src/duskz.tools/classes/duskz/tool/Convert.java index d584803..51c3e4c 100644 --- a/src/duskz.tools/classes/duskz/tool/Convert.java +++ b/src/duskz.tools/classes/duskz/tool/Convert.java @@ -19,36 +19,199 @@ */ package duskz.tool; +import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.io.PrintStream; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import javax.imageio.ImageIO; /** * Convert a few basic files - * - * @author Michael Zucchi */ public class Convert { + static void usage() { + System.err.println(""" + Usage: Convert cmd [args] + client + convert old client image files in //* to jar format .jar + map-client playersprites sprites + extract client info from combined map jar + """); + System.exit(1); + } + + static void addImage(Manifest man, String name, int gid0, BufferedImage image) { + Attributes a = new Attributes(); + int size = image.getHeight(); + int count = image.getWidth() / size; + + a.putValue("name_0", name); + a.putValue("gid_0", String.valueOf(gid0)); + a.putValue("count_0", String.valueOf(count)); + a.putValue("source_0", String.format("%s/%04d.png", name, gid0)); + a.putValue("width_0", String.valueOf(size)); + a.putValue("height_0", String.valueOf(size)); + + System.out.printf("%s: %d images @ %dx%d\n", name, count, size, size); + + a.putValue("count", "1"); + man.getEntries().put(name, a); + } + + static void copyStream(InputStream is, OutputStream os) throws IOException { + byte[] buf = new byte[4096]; + int len; + + while ((len = is.read(buf)) > 0) { + os.write(buf, 0, len); + } + } + public static void main(String[] args) throws IOException { + //args = new String[]{"client", "rc", "somedusk"}; + //args = new String[] { "map-client", "tileset.jar", "rc/somedusk/images/players.gif", "rc/somedusk/images/sprites.gif", "nowhere.jar" }; + if (args.length < 1) { + usage(); + } + + String cmd = args[0]; + switch (cmd) { + case "client": { + String rc = args[1]; + String game = args[2]; + File dir = new File(rc, game); + String[] srcs = {"images/map.gif", "images/players.gif", "images/sprites.gif"}; + BufferedImage[] images = new BufferedImage[srcs.length]; + String[] names = {"tiles", "players", "sprites"}; + int[] gid0 = {0, 0, 0}; + Manifest man = new Manifest(); + + for (int i = 0; i < srcs.length; i++) { + images[i] = ImageIO.read(new File(dir, srcs[i])); + addImage(man, names[i], gid0[i], images[i]); + } + + try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(game + ".jar"), man)) { + for (int i = 0; i < names.length; i++) { + JarEntry je = new JarEntry(names[i] + "/"); + jos.putNextEntry(je); + jos.closeEntry(); + } + for (int i = 0; i < names.length; i++) { + JarEntry ze = new JarEntry(String.format("%s/%04d.png", names[i], gid0[i])); + jos.putNextEntry(ze); + ImageIO.write(images[i], "png", jos); + jos.closeEntry(); + } + } + + break; + } + case "map-client": { + String map = args[1]; + String[] srcs = new String[]{args[2], args[3]}; + + String client = args[4]; + final String[] names = {"players", "sprites"}; + final String[] fields = {"name", "gid", "count", "width", "height"}; + int[] gid0 = {0, 0}; + BufferedImage[] images = new BufferedImage[srcs.length]; + + try (JarInputStream jis = new JarInputStream(new FileInputStream(map))) { + Manifest src = jis.getManifest(); + Manifest dst = new Manifest(); + + // copy tiles, but rename soiurce + { + Attributes a = src.getAttributes("tilesets"); + Attributes b = new Attributes(); + int count = Integer.parseInt(a.getValue("count")); + + for (int i = 0; i < count; i++) { + for (String field: fields) { + b.putValue(field + "_" + i, a.getValue(i + "_" + field)); + } + b.putValue("source_" + i, String.format("tiles/%04d.png", Integer.valueOf(a.getValue(i + "_gid")))); + } + + b.putValue("count", a.getValue("count")); + dst.getEntries().put("tiles", b); + } + + for (int i = 0; i < srcs.length; i++) { + images[i] = ImageIO.read(new File(srcs[i])); + addImage(dst, names[i], gid0[i], images[i]); + } + + try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(client), dst)) { + JarEntry se; + + // copy everything? + while ((se = jis.getNextJarEntry()) != null) { + String n = se.getName(); + if (n.matches("tiles/tiles_\\d+\\.png")) { + JarEntry de = new JarEntry(String.format("tiles/%04d.png", Integer.valueOf(n.substring(12, n.length() - 4)))); + jos.putNextEntry(de); + } else { + jos.putNextEntry(se); + } + copyStream(jis, jos); + jos.closeEntry(); + } + + // write sprites/etc + for (String name: names) { + JarEntry je = new JarEntry(name + "/"); + jos.putNextEntry(je); + jos.closeEntry(); + } + for (int i = 0; i < names.length; i++) { + JarEntry ze = new JarEntry(String.format("%s/%04d.png", names[i], gid0[i])); + jos.putNextEntry(ze); + ImageIO.write(images[i], "png", jos); + jos.closeEntry(); + } + } + } + break; + } + default: + usage(); + break; + + } + + } + + public static void junk(String[] args) throws IOException { File src = new File("/home/notzed/src/DuskRPG/DuskFiles/Dusk2.7.3"); File dst = new File("/home/notzed/dusk/game"); - + PrintStream o = new PrintStream(new File(dst, "mobs.new")); - + try (BufferedReader is = new BufferedReader(new FileReader(new File(src, "mobs")))) { while (true) { String m = is.readLine(); - + if (m == null || !m.trim().equals("mob2.3")) break; - - String name= is.readLine(); + + String name = is.readLine(); int x = Integer.valueOf(is.readLine()); int y = Integer.valueOf(is.readLine()); - + o.println("type.Mobile=" + name); o.println("map=dusk"); o.println("x=" + x); diff --git a/src/duskz.tools/classes/duskz/tool/fx/MapView.java b/src/duskz.tools/classes/duskz/tool/fx/MapView.java index 26a1bee..ca008d5 100644 --- a/src/duskz.tools/classes/duskz/tool/fx/MapView.java +++ b/src/duskz.tools/classes/duskz/tool/fx/MapView.java @@ -20,12 +20,16 @@ package duskz.tool.fx; import duskz.client.fx.DataManagerFX; import duskz.map.TileMap; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; import javafx.animation.Animation; import javafx.application.Platform; import javafx.beans.value.ChangeListener; @@ -53,7 +57,7 @@ import javafx.util.Duration; */ public class MapView extends Region implements ChangeListener { - String oldmap = "/home/notzed/src/DuskRPG/DuskFiles/Dusk2.7.3"; + String oldmap = "game-2.7.3"; TileMap map; DataManagerFX data; // TODO: tilesize on DataManagerFX @@ -110,7 +114,7 @@ public class MapView extends Region implements ChangeListener { public void handle(MouseEvent t) { if (t.getEventType() == MouseEvent.MOUSE_PRESSED) { - if (t.getButton() == MouseButton.SECONDARY) { + if (t.getButton() == MouseButton.MIDDLE) { startx = t.getX(); starty = t.getY(); hstart = hbar.getValue(); @@ -130,7 +134,9 @@ public class MapView extends Region implements ChangeListener { double fixv = (vbar.getMax() + vbar.getVisibleAmount()) / vbar.getMax(); hbar.setValue(hstart - dx * fixh); vbar.setValue(vstart - dy * fixv); + System.out.println("drag " + dx + "," + dy); t.consume(); + updateMapVisible(); } //} } else if (t.getEventType() == MouseEvent.MOUSE_RELEASED) { @@ -139,14 +145,15 @@ public class MapView extends Region implements ChangeListener { t.consume(); } } else if (t.getEventType() == MouseEvent.MOUSE_CLICKED) { - int tx = (int) ((getOriginX() + t.getX()) / tileSize / scale); - int ty = (int) ((getOriginY() + t.getY()) / tileSize / scale); - - //System.out.printf("selecting %d,%d mouse %f,%f origin %f,%f\n", tx, ty, t.getX(), t.getY(), getOriginX(), getOriginY()); - - selectionModel.setSelected(tx, ty); - // hack - requestLayout(); + if (t.getButton() == MouseButton.PRIMARY) { + int tx = (int)((getOriginX() + t.getX()) / tileSize / scale); + int ty = (int)((getOriginY() + t.getY()) / tileSize / scale); + + System.out.printf("selecting %d,%d mouse %f,%f origin %f,%f\n", tx, ty, t.getX(), t.getY(), getOriginX(), getOriginY()); + selectionModel.setSelected(tx, ty); + // hack + updateMapVisible(); + } } } }); @@ -161,7 +168,6 @@ public class MapView extends Region implements ChangeListener { super.layoutChildren(); //System.out.printf("layout children dimensions = %fx%f\n", getWidth(), getHeight()); - overlay.resize(getWidth(), getHeight()); if (map != null) { @@ -177,12 +183,12 @@ public class MapView extends Region implements ChangeListener { vbar.setVisibleAmount(getHeight()); hbar.setVisibleAmount(getWidth()); - //System.out.printf("visible %f total %f\n", vbar.getVisibleAmount(), vbar.getMax()); + vcols = (int)(getWidth() / (tileSize * scale)) + 1; + vrows = (int)(getHeight() / (tileSize * scale)) + 1; + //System.out.printf("visible %f total %f\n", vbar.getVisibleAmount(), vbar.getMax()); // create imageview objects to cover screen - if (oldw != getWidth() || oldh != getHeight()) { - vcols = (int) (getWidth() / (tileSize * scale)) + 1; - vrows = (int) (getHeight() / (tileSize * scale)) + 1; + if (oldw != getWidth() || oldh != getHeight() || graphics.getChildren().size() != vcols * vrows * map.getLayerCount()) { oldw = getWidth(); oldh = getHeight(); ObservableList c = graphics.getChildren(); @@ -211,14 +217,39 @@ public class MapView extends Region implements ChangeListener { System.out.println("trnaslate changed"); } + public InputStream getInputStream(String jar, String path) throws IOException { + JarInputStream jis = null; + try { + jis = new JarInputStream(new FileInputStream(jar)); + JarEntry je; + + while ((je = jis.getNextJarEntry()) != null) { + System.out.println("je = " + je.getName()); + if (je.getName().equals(path)) + return jis; + } + jis.close(); + throw new FileNotFoundException(path); + } catch (IOException ex) { + if (jis != null) + jis.close(); + throw ex; + } + } + public void loadMap(DataManagerFX data, String name) throws IOException { this.data = data; - try (InputStream is = data.getInputStream("maps/" + name)) { - map = TileMap.loadLayeredMap(is, name); + try (InputStream is = getInputStream(data.getSource() + ".jar", "maps/" + name)) { + setMap(TileMap.loadLayeredMap(is, name)); } - updateMap(); - requestLayout(); + } + + public void loadExternalMap(DataManagerFX data, String path) throws IOException { + this.data = data; + + // map = TileMap.loadMap(new File(path), TileMap.FORMAT_SHORT); + setMap(TileMap.loadLayered(new File(path))); } public MapSelectionModel getSelectionModel() { @@ -229,6 +260,14 @@ public class MapView extends Region implements ChangeListener { return map; } + public void setMap(TileMap map) { + this.map = map; + //updateMap(); + vbar.setValue(0); + hbar.setValue(0); + requestLayout(); + } + @Override protected double computePrefHeight(double d) { //if (map == null) @@ -261,11 +300,11 @@ public class MapView extends Region implements ChangeListener { } public int getTileX() { - return (int) (getOriginX() / tileSize / scale); + return (int)(getOriginX() / tileSize / scale); } public int getTileY() { - return (int) (getOriginY() / tileSize / scale); + return (int)(getOriginY() / tileSize / scale); } void updateMapVisible() { @@ -273,26 +312,23 @@ public class MapView extends Region implements ChangeListener { final ArrayList upper = new ArrayList<>(); int levelCount = map.getLayerCount(); + System.out.println("update visible map"); + // Animated tiles hack test // final Rectangle2D[] anims = new Rectangle2D[2]; // anims[0] = data.createTile(305, 0, 0, tileSize, tileSize).getViewport(); // anims[1] = data.createTile(304, 0, 0, tileSize, tileSize).getViewport(); // final List animated = new ArrayList<>(); - int x0 = getTileX(); int y0 = getTileY(); // y0 = Math.min(y0, map.getRows()); // y1 = Math.min(y1, map.getRows()); - //graphics.setTranslateX(-((long) getOriginX() & (tileSize - 1)) * scale); //graphics.setTranslateY(-((long) getOriginY() & (tileSize - 1)) * scale); - // TODO: set position pixel or some shit - //if (oldx0 == x0 && oldy0 == y0 && oldvcols == vcols && oldvrows == vrows) // return; - oldx0 = x0; oldy0 = y0; oldvcols = vcols; @@ -305,7 +341,7 @@ public class MapView extends Region implements ChangeListener { int ty = y + y0; for (int x = 0; x < vcols; x++) { int tx = x + x0; - ImageView iv = (ImageView) graphics.getChildren().get(x + y * vcols + l * vcols * vrows); + ImageView iv = (ImageView)graphics.getChildren().get(x + y * vcols + l * vcols * vrows); int tileid = map.getTile(l, tx, ty); if (tileid != 0) { @@ -329,7 +365,6 @@ public class MapView extends Region implements ChangeListener { } } - // Check for meta data on map region List nodes = new ArrayList(); @@ -368,10 +403,10 @@ public class MapView extends Region implements ChangeListener { String visible = map.locationVisibleScript(tx, ty); if (a != null - || j != null - || able != null - || action != null - || visible != null) { + || j != null + || able != null + || action != null + || visible != null) { Rectangle r = new Rectangle(tileSize - 4, tileSize - 4); r.setFill(null); r.setStroke(Color.RED); @@ -405,7 +440,7 @@ public class MapView extends Region implements ChangeListener { alias.getChildren().setAll(nodes); // Load animation stuff - for (Entry> e : animated.entrySet()) { + for (Entry> e: animated.entrySet()) { int root = e.getKey(); TileAnimator animator = animators.get(root); DataManagerFX.AnimSetFX set = data.getAnimSet(root); @@ -421,6 +456,7 @@ public class MapView extends Region implements ChangeListener { } } } + /* Future f; @@ -436,7 +472,6 @@ public class MapView extends Region implements ChangeListener { f = TZ.single.submit(new Update(x0, y0, 1, vcols, vrows)); }*/ - class Update implements Runnable { int x0, y0, xstep; @@ -488,7 +523,6 @@ public class MapView extends Region implements ChangeListener { // anims[0] = data.createTile(305, 0, 0, tileSize, tileSize).getViewport(); // anims[1] = data.createTile(304, 0, 0, tileSize, tileSize).getViewport(); // final List animated = new ArrayList<>(); - // Build whole map for (int l = 0; l < levelCount; l++) { for (int y = 0; y < map.getRows(); y++) { @@ -526,7 +560,6 @@ public class MapView extends Region implements ChangeListener { //for (Entity e : map.getEntities()) { // drawEntity(map.offx, map.offy, children, e); //} - Platform.runLater(new Runnable() { @Override public void run() { diff --git a/src/duskz.tools/classes/duskz/viewer/MapViewer.java b/src/duskz.tools/classes/duskz/viewer/MapViewer.java index 6de2844..56d7500 100644 --- a/src/duskz.tools/classes/duskz/viewer/MapViewer.java +++ b/src/duskz.tools/classes/duskz/viewer/MapViewer.java @@ -1,6 +1,19 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. +/** + * TileZ is a tile editor. + * Copyright (C) 2013 Michael Zucchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package duskz.viewer; @@ -36,14 +49,14 @@ public class MapViewer extends Application { stage.setScene(scene); stage.show(); - String datapath = "/home/notzed/house.jar"; - String mappath = "main"; + String datapath = "somedusk"; + String mappath = "game-2.7.3/shortmap"; try { data = new DataManagerFX(datapath); - data.open(); - mapView.loadMap(data, mappath); - + data.load(); + //mapView.loadMap(data, mappath); + mapView.loadExternalMap(data, mappath); // locationEditor.setMap(mapView.map); /* -- 2.39.2