2024-11-16 13:10:18 +01:00

469 lines
12 KiB
Java

package fr.enssat.BoulderDash.helpers;
import fr.enssat.BoulderDash.exceptions.UnknownModelException;
import fr.enssat.BoulderDash.models.RockfordModel;
import fr.enssat.BoulderDash.models.DisplayableElementModel;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* LevelLoadHelper
*
* Proceeds level load routine
* Able to deserialize level data from storage, and format it to
* internal representation To be used as a data factory from level
* model classes
*
* @author Valerian Saliou <valerian@valeriansaliou.name>
* @since 2015-06-19
*/
public class LevelLoadHelper {
private static String pathToDataStore = "./res/levels";
private String levelId = null;
private Document levelDOM;
private XPath xpathBuilder;
private SimpleDateFormat dateFormatter;
// Parsed values
private String nameValue = null;
private Date dateCreatedValue = null;
private Date dateModifiedValue = null;
private int widthSizeValue = 0;
private int heightSizeValue = 0;
private int limitsWidth = 2;
private int limitsHeight = 2;
private int limitsOffsetWidth = 1;
private int limitsOffsetHeight = 1;
private RockfordModel rockfordInstance;
private int rockfordPositionX = 0;
private int rockfordPositionY = 0;
private int diamondsToCatch;
private DisplayableElementModel[][] groundGrid;
/**
* Class constructor
*
* @param levelId Level identifier
*/
public LevelLoadHelper(String levelId) {
this.setLevelId(levelId);
this.diamondsToCatch = 0;
// Requirements
this.dateFormatter = new SimpleDateFormat("yyy-MM-dd/HH:mm:ss", Locale.ENGLISH);
if (this.levelId != null) {
// Let's go.
this.loadLevelData();
}
}
/**
* Gets level storage path
*
* @return Level path, with file extension
*/
private String getLevelPathInDataStore() {
return this.pathToDataStore + "/" + this.getLevelId() + ".xml";
}
/**
* Loads the level data into instance data space
*/
private void loadLevelData() {
this.xpathBuilder = XPathFactory.newInstance().newXPath();
String pathToData = this.getLevelPathInDataStore();
// Parse & process level data
this.parseLevelData(pathToData);
this.processLevelData();
}
/**
* Parses the level data for the given file
* Handles the task of reading and storing the parsed DOM
*
* @param pathToLevelData FS path to the level data
*/
private void parseLevelData(String pathToLevelData) {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
// Parse data in level file
this.levelDOM = documentBuilder.parse(pathToLevelData);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (org.xml.sax.SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Processes the parsed level data
*/
private void processLevelData() {
// Parse elements from structure
try {
this.processNameElement();
this.processDateElement();
this.processSizeElement();
this.processGridElement();
} catch (XPathExpressionException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
/**
* Processes the 'name' element
*/
private void processNameElement() throws XPathExpressionException {
// Returns level name value
this.nameValue = this.xpathBuilder.compile("/bd-level/name").evaluate(this.levelDOM);
}
/**
* Processes the 'date' element
*/
private void processDateElement() throws XPathExpressionException, ParseException {
// Returns level creation date value
this.dateCreatedValue = this.dateFormatter.parse(xpathBuilder.compile("/bd-level/date[@format='utc']/created").evaluate(this.levelDOM));
// Returns level modification date value
this.dateModifiedValue = this.dateFormatter.parse(this.xpathBuilder.compile("/bd-level/date[@format='utc']/modified").evaluate(this.levelDOM));
}
/**
* Processes the 'size' element
*/
private void processSizeElement() throws XPathExpressionException {
// Returns level width value
this.widthSizeValue = Integer.parseInt(this.xpathBuilder.compile("/bd-level/size/width").evaluate(this.levelDOM));
this.widthSizeValue += this.limitsWidth;
// Returns level height value
this.heightSizeValue = Integer.parseInt(this.xpathBuilder.compile("/bd-level/size/height").evaluate(this.levelDOM));
this.heightSizeValue += this.limitsHeight;
}
/**
* Processes the 'grid' element
*/
private void processGridElement() throws XPathExpressionException {
// Initialize the grid
this.groundGrid = new DisplayableElementModel[this.widthSizeValue][this.heightSizeValue];
// Populate the grid
NodeList lineNode = (NodeList) this.xpathBuilder.compile("/bd-level/grid[@state='initial']/line").evaluate(this.levelDOM, XPathConstants.NODESET);
// Parse lines
for (int y = 0; y < lineNode.getLength(); y++) {
Node currentLineNode = lineNode.item(y);
// Current line
if (currentLineNode.getNodeType() == Node.ELEMENT_NODE) {
Element currentLineElement = (Element) currentLineNode;
int lineIndex = Integer.parseInt(currentLineElement.getAttribute("index"));
NodeList rowNode = (NodeList) currentLineNode.getChildNodes();
for (int x = 0; x < rowNode.getLength(); x++) {
Node currentRowNode = rowNode.item(x);
// Current row
if (currentRowNode.getNodeType() == Node.ELEMENT_NODE) {
Element currentRowElement = (Element) currentRowNode;
int rowIndex = Integer.parseInt(currentRowElement.getAttribute("index"));
NodeList spriteNode = currentRowElement.getElementsByTagName("sprite");
if (spriteNode.getLength() > 0) {
Node currentSpriteNode = spriteNode.item(0);
if (currentSpriteNode.getNodeType() == Node.ELEMENT_NODE) {
Element currentSpriteElement = (Element) currentSpriteNode;
String currentSpriteName = currentSpriteElement.getAttribute("name");
String currentSpriteConvertibleValue = currentSpriteElement.getAttribute("convertible");
boolean currentSpriteConvertible = false;
// No name? Continue.
if(currentSpriteName == null || currentSpriteName.isEmpty()) {
continue;
}
if(currentSpriteConvertibleValue.equals("1")) {
currentSpriteConvertible = true;
}
// Process positions
int pX = rowIndex + this.limitsOffsetWidth;
int pY = lineIndex + this.limitsOffsetHeight;
try {
this.groundGrid[pX][pY] = this.constructGridElement(currentSpriteName, pX, pY, currentSpriteConvertible);
} catch (UnknownModelException e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
/**
* Constructs the grid element
*
* @param spriteName Sprite name
* @param rowIndex Position in row (horizontal axis)
* @param lineIndex Position in line (vertical axis)
*/
private DisplayableElementModel constructGridElement(String spriteName, int rowIndex, int lineIndex, boolean convertible) throws UnknownModelException {
ModelConvertHelper modelConvert = ModelConvertHelper.getInstance();
DisplayableElementModel element = modelConvert.toModel(spriteName, convertible);
// Custom actions?
switch (spriteName) {
case "diamond":
diamondsToCatch += 1;
break;
case "rockford":
this.setRockfordPositionX(rowIndex);
this.setRockfordPositionY(lineIndex);
this.setRockfordInstance((RockfordModel) element);
break;
}
return element;
}
/**
* Gets the level identifier
*
* @return Level identifier
*/
public String getLevelId() {
return this.levelId;
}
/**
* Sets the level identifier
*
* @param levelId Level identifier
*/
private void setLevelId(String levelId) {
this.levelId = levelId;
}
/**
* Gets the name value
*
* @return Name value
*/
public String getNameValue() {
return this.nameValue;
}
/**
* Sets the name value
*
* @param nameValue Name value
*/
private void setNameValue(String nameValue) {
this.nameValue = nameValue;
}
/**
* Gets the creation date value
*
* @return Creation date value
*/
public Date getDateCreatedValue() {
return this.dateCreatedValue;
}
/**
* Sets the creation date value
*
* @param dateCreatedValue Creation date value
*/
private void setDateCreatedValue(Date dateCreatedValue) {
this.dateCreatedValue = dateCreatedValue;
}
/**
* Gets the modified date value
*
* @return Modified date value
*/
public Date getDateModifiedValue() {
return this.dateModifiedValue;
}
/**
* Sets the modified date value
*
* @param dateModifiedValue Modified date value
*/
private void setDateModifiedValue(Date dateModifiedValue) {
this.dateModifiedValue = dateModifiedValue;
}
/**
* Gets the width size value
*
* @return Width size value
*/
public int getWidthSizeValue() {
return this.widthSizeValue;
}
/**
* Sets the width size value
*
* @param widthSizeValue Width size value
*/
private void setWidthSizeValue(int widthSizeValue) {
this.widthSizeValue = widthSizeValue;
}
/**
* Gets the height size value
*
* @return Height size value
*/
public int getHeightSizeValue() {
return this.heightSizeValue;
}
/**
* Sets the eight size value
*
* @param heightSizeValue Height size value
*/
private void setHeightSizeValue(int heightSizeValue) {
this.heightSizeValue = heightSizeValue;
}
/**
* Gets the horizontal position of the Rockford element
*
* @return Horizontal position of the Rockford element
*/
public int getRockfordPositionX() {
return this.rockfordPositionX;
}
/**
* Sets the horizontal position of the Rockford element
*
* @param x Horizontal position of the Rockford element
*/
public void setRockfordPositionX(int x) {
this.rockfordPositionX = x;
}
/**
* Gets the vertical position of the Rockford element
*
* @return Vertical position of the Rockford element
*/
public int getRockfordPositionY() {
return this.rockfordPositionY;
}
/**
* Sets the vertical position of the Rockford element
*
* @param y Vertical position of the Rockford element
*/
public void setRockfordPositionY(int y) {
this.rockfordPositionY = y;
}
/**
* Gets the instance of Rockford
*
* @return Rockford instance
*/
public RockfordModel getRockfordInstance() {
return this.rockfordInstance;
}
/**
* Sets the instance of Rockford
*
* @param rockfordInstance Rockford instance
*/
public void setRockfordInstance(RockfordModel rockfordInstance) {
this.rockfordInstance = rockfordInstance;
}
/**
* Gets the ground grid
*
* @return Ground grid
*/
public DisplayableElementModel[][] getGroundGrid() {
return this.groundGrid;
}
/**
* Sets the ground grid
*
* @param groundGrid Ground grid
*/
private void setGroundGrid(DisplayableElementModel[][] groundGrid) {
this.groundGrid = groundGrid;
}
/**
* Gets the number of Diamonds to catch
* @return number of Diamonds to catch
*/
public int getDiamondsToCatch() {
return diamondsToCatch;
}
/**
* Sets the number of Diamonds to catch
* @param diamondsToCatch
*/
public void setDiamondsToCatch(int diamondsToCatch) {
this.diamondsToCatch = diamondsToCatch;
}
}