package vooga.rts.leveleditor.components; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.imageio.ImageIO; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import util.Location; import vooga.rts.util.Pixmap; /** * this class is responsible for generate the map file * @author Richard Yang * */ public class MapSaver { /** * the string of id */ public static final String ID = "ID"; /** * the string of x */ public static final String X = "X"; /** * the string of y */ public static final String Y = "Y"; /** * the string of z */ public static final String Z = "Z"; /** * the string of name */ public static final String NAME = "name"; /** * the string of image */ public static final String IMAGE = "image"; /** * the string of amount */ public static final String AMOUNT = "amount"; private DocumentBuilderFactory myFactory; private DocumentBuilder myBuilder; private Document myDocument; private EditableMap mySavingMap; /** * constructor * @param map the map we want to save * @throws ParserConfigurationException xml parser exception */ public MapSaver(EditableMap map) throws ParserConfigurationException { myFactory = DocumentBuilderFactory.newInstance(); myBuilder = myFactory.newDocumentBuilder(); myDocument = myBuilder.newDocument(); mySavingMap = map; } /** * generate a map file * @param objectiveFile the objective file * @param Exception exception of this method * */ public void generateMapFile(File objectiveFile) throws Exception { String filePath = objectiveFile.getPath(); String fileName = objectiveFile.getName(); myDocument = myBuilder.newDocument(); String relativePath = filePath.substring(0, filePath.indexOf(fileName)); String xmlPath = relativePath + fileName + "/" + fileName + ".xml"; String imagePath = relativePath + fileName + "/images"; File mapFolder = new File(relativePath + fileName); mapFolder.mkdirs(); File mapXMLFile = new File(xmlPath); File imageFolder = new File(imagePath); imageFolder.mkdirs(); storeImages(imagePath); Element root = myDocument.createElement("Map"); myDocument.appendChild(root); appendInfo(root); appendResourceInfo(root); appendTile(root); appendTerrain(root); appendResource(root); TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //transformer.setOutputProperty("http://xml.apache.org/xslt}indent-amount", "2"); FileOutputStream out = new FileOutputStream(mapXMLFile); StreamResult result = new StreamResult(out); transformer.transform(new DOMSource(myDocument), result); } /** * store the images into certain path * @param path path we want to store */ private void storeImages(String path) { storeTileImages(path); storeTerrainImages(path); storeResourceImages(path); } /** * store all tile images * @param path objective path */ private void storeTileImages(String path) { File tileFolder = new File(path + "/tiles"); tileFolder.mkdirs(); String tileImagePath = path + "/tiles/"; Map<String, Pixmap> tileInformation = new HashMap<String, Pixmap>(); for (int i = 0; i < mySavingMap.getMyXsize(); i++) { for (int j = 0; j < mySavingMap.getMyYsize(); j++) { if (mySavingMap.getMyTile(i, j).getMyID() != 0) { String imageName = mySavingMap.getMyTile(i, j).getMyImageName(); if (!tileInformation.containsKey(imageName)) { Pixmap currentImage = mySavingMap.getMyTile(i, j).getImage(); tileInformation.put(imageName, currentImage); } } } } for (String str : tileInformation.keySet()) { File bufferFile = new File(tileImagePath + str); String format = getFileFormat(str); try { ImageIO.write((BufferedImage)tileInformation.get(str).getImage(), format, bufferFile); } catch (IOException e) { e.printStackTrace(); } } } /** * store all terrain images * @param path objective path */ private void storeTerrainImages(String path) { File tileFolder = new File(path + "/terrains"); tileFolder.mkdirs(); String tileImagePath = path + "/terrains/"; Map<String, BufferedImage> terrainInformation = new HashMap<String, BufferedImage>(); for (int i = 0; i < mySavingMap.getTerrainSize(); i++) { EditableTerrain ter = mySavingMap.getTerrain(i); String myImageName = ter.getMyImageName(); BufferedImage myImage = (BufferedImage)ter.getMyImage(); if (!terrainInformation.containsKey(myImageName)) { terrainInformation.put(myImageName, myImage); } } for (String str : terrainInformation.keySet()) { File bufferFile = new File(tileImagePath + str); String format = getFileFormat(str); try { ImageIO.write(terrainInformation.get(str), format, bufferFile); } catch (IOException e) { e.printStackTrace(); } } } /** * store all resource images * @param path objective path */ private void storeResourceImages(String path) { File tileFolder = new File(path + "/resources"); tileFolder.mkdirs(); String tileImagePath = path + "/resources/"; Map<String, BufferedImage> resourceInformation = new HashMap<String, BufferedImage>(); for (int i = 0; i < mySavingMap.getResourceSize(); i++) { EditableResource res = mySavingMap.getResource(i); String myImageName = res.getMyImageName(); BufferedImage myImage = (BufferedImage)res.getMyImage(); if (!resourceInformation.containsKey(myImageName)) { resourceInformation.put(myImageName, myImage); } } for (String str : resourceInformation.keySet()) { File bufferFile = new File(tileImagePath + str); String format = getFileFormat(str); try { ImageIO.write(resourceInformation.get(str), format, bufferFile); } catch (IOException e) { e.printStackTrace(); } } } /** * get the format of a file based on its name * @param fileName the name of the file * @return String */ private String getFileFormat(String fileName) { return fileName.substring(fileName.indexOf(".") + 1); } /** * append the information of this map in xml file * @param root root element */ private void appendInfo(Element root) { Element info = myDocument.createElement("MapInfo"); Element name = myDocument.createElement("Name"); name.appendChild(myDocument.createTextNode(mySavingMap.getMapName())); info.appendChild(name); Element description = myDocument.createElement("Desc"); description.appendChild(myDocument.createTextNode(mySavingMap.getMapDescription())); info.appendChild(description); Element players = myDocument.createElement("Players"); players.setAttribute("number", mySavingMap.getMyPlayerNumber() + ""); for (Integer i : mySavingMap.getAllPlayers().keySet()) { Location loc = mySavingMap.getAllPlayers().get(i); int x = (int)loc.getX(); int y = (int)loc.getY(); Element myPlayer = myDocument.createElement("Player"); myPlayer.setAttribute(ID, i + ""); myPlayer.setAttribute(X, x + ""); myPlayer.setAttribute(Y, y + ""); players.appendChild(myPlayer); } info.appendChild(players); root.appendChild(info); } /** * append the resource information of this map in xml file * @param root root element */ private void appendResourceInfo(Element root) { Element resourceInfo = myDocument.createElement("Resourceinfo"); Element sizeInfo = myDocument.createElement("SizeInfo"); Element tileIndex = myDocument.createElement("tileindex"); Element terrainIndex = myDocument.createElement("terrainindex"); Element resourceIndex = myDocument.createElement("resourceIndex"); Element tileSize = myDocument.createElement("tilesize"); tileSize.setAttribute("width", mySavingMap.getMyTileWidth() + ""); tileSize.setAttribute("height", mySavingMap.getMyTileHeight() + ""); sizeInfo.appendChild(tileSize); Element tileAmount = myDocument.createElement("tileamount"); tileAmount.setAttribute("X", mySavingMap.getMyXsize() + ""); tileAmount.setAttribute("Y", mySavingMap.getMyYsize() + ""); sizeInfo.appendChild(tileAmount); appendTileIndex(tileIndex); appendTerrainIndex(terrainIndex); appendResourceIndex(resourceIndex); resourceInfo.appendChild(sizeInfo); resourceInfo.appendChild(tileIndex); resourceInfo.appendChild(terrainIndex); resourceInfo.appendChild(resourceIndex); root.appendChild(resourceInfo); } /** * append the tile index * @param tileIndex root element */ private void appendTileIndex(Element tileIndex) { Set<Integer> myTileIndex = new HashSet<Integer>(); for (int i = 0; i < mySavingMap.getMyXsize(); i++) { for (int j = 0; j < mySavingMap.getMyYsize(); j++) { EditableTile currentTile = mySavingMap.getMyTile(i, j); int id = currentTile.getMyID(); if (!myTileIndex.contains(id) && id != 0) { myTileIndex.add(id); Element newTile = myDocument.createElement("tiletype"); newTile.setAttribute(ID, id + ""); newTile.setAttribute(IMAGE, currentTile.getMyImageName()); newTile.setAttribute(NAME, currentTile.getMyName()); tileIndex.appendChild(newTile); } } } } /** * append the terrain index * @param terrainIndex root element */ private void appendTerrainIndex(Element terrainIndex) { Set<Integer> myTerrainIndex = new HashSet<Integer>(); for (int i = 0; i < mySavingMap.getTerrainSize(); i++) { EditableTerrain currentTerrain = mySavingMap.getTerrain(i); int id = currentTerrain.getMyID(); if (!myTerrainIndex.contains(id)) { myTerrainIndex.add(id); Element newTerrain = myDocument.createElement("terraintype"); newTerrain.setAttribute(ID, id + ""); newTerrain.setAttribute(IMAGE, currentTerrain.getMyImageName()); newTerrain.setAttribute(NAME, currentTerrain.getMyName()); newTerrain.setAttribute("walkAbility", currentTerrain.getMyWalkAbility() + ""); terrainIndex.appendChild(newTerrain); } } } /** * append resource index * @param resourceIndex root element */ private void appendResourceIndex(Element resourceIndex) { Set<Integer> myResourceIndex = new HashSet<Integer>(); for (int i = 0; i < mySavingMap.getResourceSize(); i++) { EditableResource currentResource = mySavingMap.getResource(i); int id = currentResource.getMyID(); if (!myResourceIndex.contains(id)) { myResourceIndex.add(id); Element newResource = myDocument.createElement("resourcetype"); newResource.setAttribute(ID, id + ""); newResource.setAttribute(IMAGE, currentResource.getMyImageName()); newResource.setAttribute(NAME, currentResource.getType()); newResource.setAttribute(AMOUNT, currentResource.getMyAmount() + ""); resourceIndex.appendChild(newResource); } } } /** * append the tile this map in xml file * @param root root element */ private void appendTile(Element root) { Element tile = myDocument.createElement("tiles"); int x = mySavingMap.getMyXsize(); int y = mySavingMap.getMyYsize(); for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { EditableTile bufferTile = mySavingMap.getMyTile(i, j); Element currentTile = myDocument.createElement("tile"); currentTile.setAttribute("ID", bufferTile.getMyID() + ""); tile.appendChild(currentTile); } } root.appendChild(tile); } /** * append the terrains of this map in xml file * @param root root element */ private void appendTerrain(Element root) { Element terrains = myDocument.createElement("terrains"); for (int i = 0; i < mySavingMap.getTerrainSize(); i++) { EditableTerrain ter = mySavingMap.getTerrain(i); int id = ter.getMyID(); int x = (int)ter.getWorldLocation().getX(); int y = (int)ter.getWorldLocation().getY(); int z = (int)ter.getWorldLocation().getZ(); Element newTerrain = myDocument.createElement("terrain"); newTerrain.setAttribute(ID, id + ""); newTerrain.setAttribute(X, x + ""); newTerrain.setAttribute(Y, y + ""); newTerrain.setAttribute(Z, z + ""); terrains.appendChild(newTerrain); } root.appendChild(terrains); } /** * append the resource information of this map in xml file * @param root root element */ private void appendResource(Element root) { Element resources = myDocument.createElement("Resources"); for (int i = 0; i < mySavingMap.getResourceSize(); i++) { EditableResource res = mySavingMap.getResource(i); int id = res.getMyID(); int x = (int)res.getWorldLocation().getX(); int y = (int)res.getWorldLocation().getY(); int z = (int)res.getWorldLocation().getZ(); int amount = (int)res.getMyAmount(); Element newResource = myDocument.createElement("resource"); newResource.setAttribute("ID", id + ""); newResource.setAttribute("X", x + ""); newResource.setAttribute("Y", y + ""); newResource.setAttribute("Z", z + ""); newResource.setAttribute(AMOUNT, amount + ""); resources.appendChild(newResource); } root.appendChild(resources); } }