diff --git a/src/main/java/cr0s/warpdrive/config/XmlPreprocessor.java b/src/main/java/cr0s/warpdrive/config/XmlPreprocessor.java index de28dac2..1805eb75 100644 --- a/src/main/java/cr0s/warpdrive/config/XmlPreprocessor.java +++ b/src/main/java/cr0s/warpdrive/config/XmlPreprocessor.java @@ -1,9 +1,12 @@ package cr0s.warpdrive.config; +import java.util.ArrayList; import java.util.Map.Entry; import java.util.TreeMap; +import org.w3c.dom.Attr; import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -12,7 +15,7 @@ import cr0s.warpdrive.WarpDrive; public class XmlPreprocessor { - + /** * Will check the given element for a mod attribute and return a string of all the ones that are not loaded, separated by commas * @@ -22,30 +25,30 @@ public class XmlPreprocessor { * @throws InvalidXmlException */ public static ModCheckResults checkModRequirements(Element e) { - + ModCheckResults modErrors = new ModCheckResults(); - + for (String mod : e.getAttribute("mods").split(",")) { - + //TODO: add version check - - + + if (mod.isEmpty()) continue; - + if (mod.startsWith("!")) { - + if (Loader.isModLoaded(mod.substring(1))) modErrors.addMod(mod, "loaded"); - + } else if (!Loader.isModLoaded(mod)) modErrors.addMod(mod, "not loaded"); - + } - + return modErrors; } - + /** * Goes through every child node of the given node, and if it is an element and fails checkModRequirements() it is removed * @@ -53,61 +56,194 @@ public class XmlPreprocessor { * @throws InvalidXmlException */ public static void doModReqSanitation(Node base) { - + NodeList children = base.getChildNodes(); - + for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); - + if (child instanceof Element) { - + ModCheckResults res = checkModRequirements((Element) child); - + if (!res.isEmpty()) { base.removeChild(child); WarpDrive.logger.info("Removed child element " + child.getBaseURI() + " of element " + base.getBaseURI() + ", results: " + res); } else { - + doModReqSanitation(child); + + } + + } + } + + } + + public static void doLogicPreprocessing(Node root) throws InvalidXmlException { + + + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) + doLogicPreprocessing(children.item(i)); + + if (root.getNodeType() == Node.ELEMENT_NODE && ((Element) root).getTagName().equalsIgnoreCase("for")) { + + Element forTag = (Element) root; + + String varName = forTag.getAttribute("variable"); + if(varName.isEmpty()) + throw new InvalidXmlException("A for tag must include a variable attribute!"); + + //In supersedes from + if (forTag.hasAttribute("in")) { + String inOptions = forTag.getAttribute("in"); + + for(String input : inOptions.split(",")) { + + NodeList allChildren = root.getChildNodes(); + for(int chI = 0; chI < allChildren.getLength(); chI ++) { + + Node copy = getCopyVarReplace(allChildren.item(chI), varName, input); + root.getParentNode().appendChild(copy); + + } + + } + + } else { + + String fromStr = forTag.getAttribute("from"); + String toStr = forTag.getAttribute("to"); + + if (toStr.isEmpty() || fromStr.isEmpty()) + throw new InvalidXmlException("If a for doesnt have an in attr, it must have a from and to!"); + + int from, to; + try { + from = Integer.parseInt(fromStr); + to = Integer.parseInt(toStr); + } catch (NumberFormatException e) { + throw new InvalidXmlException(e); + } + + for (; from <= to; from++) { + + NodeList allChildren = root.getChildNodes(); + for (int chI = 0; chI < allChildren.getLength(); chI++) { + + Node copy = getCopyVarReplace(allChildren.item(chI), varName, "" + from); + root.getParentNode().appendChild(copy); + + } + + } + + } + + //Remove the old node + root.getParentNode().removeChild(root); + + + } + + } + + private static Node getCopyVarReplace(Node toCopy, String varName, String value) { + + Node copy = toCopy.cloneNode(true); + replaceVar(copy, varName, value); + + return copy; + } + + private static void replaceVar(Node root, String varName, String value) { + + ArrayList toRemove = new ArrayList(); + ArrayList toAdd = new ArrayList(); + + if (root.getNodeType() == Node.ELEMENT_NODE) { + + //First replace attributes + NamedNodeMap attrs = root.getAttributes(); + for (int i = 0; i < attrs.getLength(); i++) { + + Attr attr = (Attr) attrs.item(i); + String name = attr.getName(); + String newName = name.replace("%" + varName + "%", value); + + if (name.equals(newName)) { + + //Easy, just adjust value + attr.setValue(attr.getValue().replace("%" + varName + "%", value)); + + } else { + + //The name changed + toRemove.add(name); + + Attr newAttr = attr.getOwnerDocument().createAttribute(newName); + newAttr.setValue(attr.getValue().replace("%" + varName + "%", value)); + toAdd.add(newAttr); } } + + //Now do the adds and removals + for (String attr : toRemove) + attrs.removeNamedItem(attr); + + for (Attr attr : toAdd) + attrs.setNamedItem(attr); + } + + //Now that Attributes are done, go through all of the children + + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + + switch (child.getNodeType()) { + case Node.ELEMENT_NODE://Recurse on the element + replaceVar(child, varName, value); + break; + case Node.TEXT_NODE: + child.setTextContent(child.getTextContent().replace("%" + varName + "%", value)); + break; + + } } } - - public static void doLogicPreprocessing(Element root) { - - } - + public static class ModCheckResults { - + private TreeMap mods; - + public ModCheckResults() { mods = new TreeMap(); } - + public void addMod(String name, String error) { mods.put(name, error); } - + public boolean isEmpty() { return mods.isEmpty(); } - + @Override public String toString() { String s = "{"; - + for (Entry e : mods.entrySet()) s = s + e.getKey() + ": " + e.getValue() + ", "; - + return s + "}"; - + } - + } - + } diff --git a/src/main/java/cr0s/warpdrive/config/filler/FillerManager.java b/src/main/java/cr0s/warpdrive/config/filler/FillerManager.java index a1d044b2..44ddfaed 100644 --- a/src/main/java/cr0s/warpdrive/config/filler/FillerManager.java +++ b/src/main/java/cr0s/warpdrive/config/filler/FillerManager.java @@ -20,12 +20,12 @@ import cr0s.warpdrive.config.XmlPreprocessor; import cr0s.warpdrive.config.XmlPreprocessor.ModCheckResults; public class FillerManager { - + private static TreeMap fillerSets = new TreeMap(); - + // Stores extra dependency information static TreeMap> fillerSetsAdditions = new TreeMap>(); - + /* TODO dead code? // FillerSets that are guaranteed to exist public static final String COMMON_ORES = "commonOres"; @@ -35,25 +35,25 @@ public class FillerManager { public static final String NETHER = "nether"; public static final String END = "end"; /**/ - + public static void loadOres(String oreConfDirectory) { loadOres(new File(oreConfDirectory)); } - + public static void loadOres(File dir) { // directory is created by caller, so it can copy default files if any - + if (!dir.isDirectory()) { throw new IllegalArgumentException("File path " + dir.getName() + " must be a directory!"); } - + File[] files = dir.listFiles(new FilenameFilter() { @Override public boolean accept(File file_notUsed, String name) { return name.startsWith("filler") && name.endsWith(".xml"); } }); - + for(File file : files) { try { WarpDrive.logger.info("Loading filler data file " + file.getName() + "..."); @@ -65,38 +65,39 @@ public class FillerManager { } } } - + private static void loadXmlFillerFile(File file) throws InvalidXmlException, SAXException, IOException { - + Document base = WarpDriveConfig.getXmlDocumentBuilder().parse(file); - + ModCheckResults res = XmlPreprocessor.checkModRequirements(base.getDocumentElement()); - + if (!res.isEmpty()) { WarpDrive.logger.info("Skippping filler data file " + file.getName() + " because of: " + res); return; } - + // Remove elements based on mod reqs sanitation XmlPreprocessor.doModReqSanitation(base); - + XmlPreprocessor.doLogicPreprocessing(base); + // Initially add FillerSets NodeList nodesFillerSet = base.getElementsByTagName("FillerSet"); for (int i = 0; i < nodesFillerSet.getLength(); i++) { - + Element elementFillerSet = (Element) nodesFillerSet.item(i); - + String group = elementFillerSet.getAttribute("group"); if (group.isEmpty()) { throw new InvalidXmlException("FillerSet " + i + " is missing a group attribute!"); } - + FillerSet fillerSet = fillerSets.get(group); if (fillerSet == null) { fillerSet = new FillerSet(group); fillerSets.put(group, fillerSet); } - + if (elementFillerSet.hasAttribute("fillerSets")) { ArrayList setUnresolvedDeps = fillerSetsAdditions.get(fillerSet); if (setUnresolvedDeps == null) { @@ -105,56 +106,56 @@ public class FillerManager { } setUnresolvedDeps.addAll(Arrays.asList(elementFillerSet.getAttribute("import").split(","))); } - + fillerSet.loadFromXmlElement(elementFillerSet); } } - + public static void finishLoading() { - + while (!fillerSetsAdditions.isEmpty()) { attemptDependencyFilling(fillerSetsAdditions); } - + // When everything is done, finalize for (FillerSet fillerSet : fillerSets.values()) { fillerSet.finishContruction(); } } - + private static void attemptDependencyFilling(TreeMap> fillerSetsDeps) { - + ArrayList toRemove = new ArrayList(); - + for (Entry> entry : fillerSetsDeps.entrySet()) { - + for (String dep : entry.getValue()) { - + if (!fillerSets.containsKey(dep)) { - + WarpDrive.logger.error("A fillerSet " + entry.getKey() + " has a dependency that doesnt exist!"); fillerSets.remove(entry.getKey().getName()); toRemove.add(entry.getKey()); - + } else if (fillerSetsDeps.containsKey(fillerSets.get(dep))) { //Skip until it is loaded } else { - + entry.getKey().loadFrom(fillerSets.get(dep)); toRemove.add(entry.getKey()); } } } - + for (FillerSet set : toRemove) { fillerSetsDeps.remove(set); } } - + public static FillerSet getFillerSet(String name) { return fillerSets.get(name); } - + /* TODO dead code? public static class BlockComparator implements Comparator { diff --git a/src/main/java/cr0s/warpdrive/config/structures/StructureManager.java b/src/main/java/cr0s/warpdrive/config/structures/StructureManager.java index 8d81a056..82aa44ce 100644 --- a/src/main/java/cr0s/warpdrive/config/structures/StructureManager.java +++ b/src/main/java/cr0s/warpdrive/config/structures/StructureManager.java @@ -19,74 +19,75 @@ import cr0s.warpdrive.config.XmlPreprocessor.ModCheckResults; public class StructureManager { - + private static ArrayList stars = new ArrayList(); private static ArrayList moons = new ArrayList(); private static ArrayList gasClouds = new ArrayList(); private static ArrayList asteroids = new ArrayList(); - + public static void loadStructures(String structureConfDir) { loadStructures(new File(structureConfDir)); } - + public static void loadStructures(File dir) { - + dir.mkdir(); - + if (!dir.isDirectory()) { throw new IllegalArgumentException("File path " + dir.getPath() + " must be a directory!"); } - + File[] files = dir.listFiles(new FilenameFilter() { @Override public boolean accept(File file_notUsed, String name) { return name.startsWith("structure") && name.endsWith(".xml"); } }); - + for (File file : files) { try { - + WarpDrive.logger.info("Loading structure data file " + file.getName()); - + loadXmlStructureFile(file); - + WarpDrive.logger.info("Finished loading structure data file " + file.getName()); - + } catch (Exception e) { WarpDrive.logger.error("Error loading file " + file.getName() + ": " + e.getMessage()); e.printStackTrace(); } } } - + private static void loadXmlStructureFile(File f) throws SAXException, IOException, InvalidXmlException { Document base = WarpDriveConfig.getXmlDocumentBuilder().parse(f); - + ModCheckResults res = XmlPreprocessor.checkModRequirements(base.getDocumentElement()); - + if (!res.isEmpty()) { WarpDrive.logger.info("Skippping structure data file " + f.getName() + " because of: " + res); return; } - + XmlPreprocessor.doModReqSanitation(base); - + XmlPreprocessor.doLogicPreprocessing(base); + NodeList structures = base.getElementsByTagName("structure"); for (int i = 0; i < structures.getLength(); i++) { - + Element struct = (Element) structures.item(i); - + String group = struct.getAttribute("group"); String name = struct.getAttribute("name"); - + WarpDrive.logger.info("Loading structure " + name); - + if (group.isEmpty()) throw new InvalidXmlException("Structure must have a group!"); - + int radius = 0; - + if (group.equalsIgnoreCase("star")) { Star s = new Star(radius); s.loadFromXmlElement(struct); @@ -102,7 +103,7 @@ public class StructureManager { } } } - + public static DeployableStructure getStructure(Random random, final String name, final String type) { if (name == null || name.length() == 0) { if (type == null || type.length() == 0) { @@ -120,23 +121,23 @@ public class StructureManager { return star; } } - + // not found or nothing defined => return null return null; } - + public static DeployableStructure getStar(Random random, final String name) { return getStructure(random, name, "star"); } - + public static DeployableStructure getMoon(Random random, final String name) { return getStructure(random, name, "moon"); } - + public static DeployableStructure getAsteroid(Random random, final String name) { return getStructure(random, name, "asteroid"); } - + public static DeployableStructure getGasCloud(Random random, final String name) { return getStructure(random, name, "cloud"); }