@@ -482,7 +482,18 @@ private static void readProperties(NodeList children, Properties props) {
482482 }
483483 }
484484 if (value != null ) {
485- props .setProperty (key , value );
485+ final String typeStr = getAttributeValue (child , "type" );
486+ if (typeStr != null && !typeStr .isEmpty ()) {
487+ try {
488+ org .mapeditor .core .PropertyType type =
489+ org .mapeditor .core .PropertyType .fromValue (typeStr );
490+ props .setProperty (key , value , type );
491+ } catch (IllegalArgumentException e ) {
492+ props .setProperty (key , value );
493+ }
494+ } else {
495+ props .setProperty (key , value );
496+ }
486497 }
487498 } else if ("properties" .equals (child .getNodeName ())) {
488499 readProperties (child .getChildNodes (), props );
@@ -656,6 +667,21 @@ private TileLayer readLayer(Node t) throws Exception {
656667 ml .setOpacity (Float .parseFloat (opacity ));
657668 }
658669
670+ final String tintColor = getAttributeValue (t , "tintcolor" );
671+ if (tintColor != null ) {
672+ ml .setTintcolor (tintColor );
673+ }
674+
675+ final double parallaxx = getDoubleAttribute (t , "parallaxx" , 1.0 );
676+ if (parallaxx != 1.0 ) {
677+ ml .setParallaxx (parallaxx );
678+ }
679+
680+ final double parallaxy = getDoubleAttribute (t , "parallaxy" , 1.0 );
681+ if (parallaxy != 1.0 ) {
682+ ml .setParallaxy (parallaxy );
683+ }
684+
659685 readProperties (t .getChildNodes (), ml .getProperties ());
660686
661687 for (Node child = t .getFirstChild (); child != null ;
@@ -665,7 +691,66 @@ private TileLayer readLayer(Node t) throws Exception {
665691 String encoding = getAttributeValue (child , "encoding" );
666692 String comp = getAttributeValue (child , "compression" );
667693
668- if ("base64" .equalsIgnoreCase (encoding )) {
694+ // Check for chunk children (infinite maps)
695+ boolean hasChunks = false ;
696+ for (Node chunkCheck = child .getFirstChild (); chunkCheck != null ;
697+ chunkCheck = chunkCheck .getNextSibling ()) {
698+ if ("chunk" .equalsIgnoreCase (chunkCheck .getNodeName ())) {
699+ hasChunks = true ;
700+ break ;
701+ }
702+ }
703+
704+ if (hasChunks ) {
705+ // Infinite map: compute bounding box from all chunks
706+ int minX = Integer .MAX_VALUE , minY = Integer .MAX_VALUE ;
707+ int maxX = Integer .MIN_VALUE , maxY = Integer .MIN_VALUE ;
708+ for (Node chunkNode = child .getFirstChild (); chunkNode != null ;
709+ chunkNode = chunkNode .getNextSibling ()) {
710+ if ("chunk" .equalsIgnoreCase (chunkNode .getNodeName ())) {
711+ int cx = getAttribute (chunkNode , "x" , 0 );
712+ int cy = getAttribute (chunkNode , "y" , 0 );
713+ int cw = getAttribute (chunkNode , "width" , 0 );
714+ int ch = getAttribute (chunkNode , "height" , 0 );
715+ minX = Math .min (minX , cx );
716+ minY = Math .min (minY , cy );
717+ maxX = Math .max (maxX , cx + cw );
718+ maxY = Math .max (maxY , cy + ch );
719+ }
720+ }
721+ int totalWidth = maxX - minX ;
722+ int totalHeight = maxY - minY ;
723+ ml = new TileLayer (new java .awt .Rectangle (minX , minY , totalWidth , totalHeight ));
724+ ml .setId (layerId );
725+ ml .setName (getAttributeValue (t , "name" ));
726+ if (opacity != null ) {
727+ ml .setOpacity (Float .parseFloat (opacity ));
728+ }
729+ if (tintColor != null ) {
730+ ml .setTintcolor (tintColor );
731+ }
732+ if (parallaxx != 1.0 ) {
733+ ml .setParallaxx (parallaxx );
734+ }
735+ if (parallaxy != 1.0 ) {
736+ ml .setParallaxy (parallaxy );
737+ }
738+ readProperties (t .getChildNodes (), ml .getProperties ());
739+
740+ // Read each chunk
741+ for (Node chunkNode = child .getFirstChild (); chunkNode != null ;
742+ chunkNode = chunkNode .getNextSibling ()) {
743+ if (!"chunk" .equalsIgnoreCase (chunkNode .getNodeName ())) {
744+ continue ;
745+ }
746+ int cx = getAttribute (chunkNode , "x" , 0 );
747+ int cy = getAttribute (chunkNode , "y" , 0 );
748+ int cw = getAttribute (chunkNode , "width" , 0 );
749+ int ch = getAttribute (chunkNode , "height" , 0 );
750+
751+ readChunkData (ml , chunkNode , encoding , comp , cx , cy , cw , ch );
752+ }
753+ } else if ("base64" .equalsIgnoreCase (encoding )) {
669754 Node cdata = child .getFirstChild ();
670755 if (cdata != null ) {
671756 String enc = cdata .getNodeValue ().trim ();
@@ -777,6 +862,74 @@ private TileLayer readLayer(Node t) throws Exception {
777862
778863
779864
865+ /**
866+ * Reads tile data from a chunk node and places tiles in the layer at the
867+ * correct position.
868+ */
869+ private void readChunkData (TileLayer ml , Node chunkNode , String encoding ,
870+ String comp , int cx , int cy , int cw , int ch ) throws IOException {
871+ if ("base64" .equalsIgnoreCase (encoding )) {
872+ Node cdata = chunkNode .getFirstChild ();
873+ if (cdata != null ) {
874+ String enc = cdata .getNodeValue ().trim ();
875+ byte [] dec = DatatypeConverter .parseBase64Binary (enc );
876+ ByteArrayInputStream bais = new ByteArrayInputStream (dec );
877+ InputStream is ;
878+
879+ if ("gzip" .equalsIgnoreCase (comp )) {
880+ is = new GZIPInputStream (bais , cw * ch * 4 );
881+ } else if ("zlib" .equalsIgnoreCase (comp )) {
882+ is = new InflaterInputStream (bais );
883+ } else if (comp != null && !comp .isEmpty ()) {
884+ throw new IOException ("Unrecognized compression method \" " + comp + "\" for chunk" );
885+ } else {
886+ is = bais ;
887+ }
888+
889+ for (int y = 0 ; y < ch ; y ++) {
890+ for (int x = 0 ; x < cw ; x ++) {
891+ int tileId = 0 ;
892+ tileId |= is .read ();
893+ tileId |= is .read () << Byte .SIZE ;
894+ tileId |= is .read () << Byte .SIZE * 2 ;
895+ tileId |= is .read () << Byte .SIZE * 3 ;
896+
897+ setTileAtFromTileId (ml , cy + y , cx + x , tileId );
898+ }
899+ }
900+ }
901+ } else if ("csv" .equalsIgnoreCase (encoding )) {
902+ String csvText = chunkNode .getTextContent ();
903+ String [] csvTileIds = csvText .trim ().split ("[\\ s]*,[\\ s]*" );
904+
905+ for (int y = 0 ; y < ch ; y ++) {
906+ for (int x = 0 ; x < cw ; x ++) {
907+ String gid = csvTileIds [x + y * cw ];
908+ long tileId = Long .parseLong (gid );
909+ setTileAtFromTileId (ml , cy + y , cx + x , (int ) tileId );
910+ }
911+ }
912+ } else {
913+ int x = 0 , y = 0 ;
914+ for (Node dataChild = chunkNode .getFirstChild (); dataChild != null ;
915+ dataChild = dataChild .getNextSibling ()) {
916+ if ("tile" .equalsIgnoreCase (dataChild .getNodeName ())) {
917+ int tileId = getAttribute (dataChild , "gid" , -1 );
918+ setTileAtFromTileId (ml , cy + y , cx + x , tileId );
919+
920+ x ++;
921+ if (x == cw ) {
922+ x = 0 ;
923+ y ++;
924+ }
925+ if (y == ch ) {
926+ break ;
927+ }
928+ }
929+ }
930+ }
931+ }
932+
780933 /**
781934 * Helper method to set the tile based on its global id.
782935 *
0 commit comments