Integrating WorldGeneration (wip)
Fixed fillerSet dependencies impacting UndergroundBiomes fillerSets Integrated XMLpreprocessor Refactored mod requirement handling Refactored RandomCollection Fixed OrbShell name overwriting Orb name Updated asteroid attributes: - minCoreSize -> minCoreCount - maxCoreSize -> maxCoreCount - coreRad -> relativeCoreRadius Updated default structures for stars and asteroids
This commit is contained in:
parent
fa48d71699
commit
9fe205ba08
18 changed files with 837 additions and 726 deletions
141
src/main/java/cr0s/warpdrive/config/RandomCollection.java
Normal file
141
src/main/java/cr0s/warpdrive/config/RandomCollection.java
Normal file
|
@ -0,0 +1,141 @@
|
|||
package cr0s.warpdrive.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Random;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import cr0s.warpdrive.WarpDrive;
|
||||
|
||||
/**
|
||||
* Collection of elements with weights. Helps to select element with controlled odds.
|
||||
*
|
||||
* @author ncrashed
|
||||
*
|
||||
* @param <E>
|
||||
*/
|
||||
public class RandomCollection<E extends XmlRepresentable> {
|
||||
private final NavigableMap<Double, E> weightMap = new TreeMap<Double, E>();
|
||||
private double totalWeight = 0;
|
||||
private final NavigableMap<Double, E> ratioMap = new TreeMap<Double, E>();
|
||||
private double totalRatio = 0;
|
||||
private final ArrayList<E> list = new ArrayList<E>();
|
||||
|
||||
/**
|
||||
* Add new object and its weight.
|
||||
*
|
||||
* @param weight
|
||||
* Used for random pick. The higher the value is relatively to others, the higher odds of choosing the object.
|
||||
* @param object
|
||||
* Object to add
|
||||
*/
|
||||
public void addWeight(double weight, E object) {
|
||||
if (weight <= 0) {
|
||||
WarpDrive.logger.warn("Weight is negative or zero, skipping " + object);
|
||||
return;
|
||||
}
|
||||
totalWeight += weight;
|
||||
weightMap.put(totalWeight, object);
|
||||
list.add(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new object and its ratio. Warning: if total ratio goes higher than 1.0, element won't be added to collection.
|
||||
*
|
||||
* @param ratio
|
||||
* Chance of random pick in range (0, 1.0]. In contrast to weights, ratio is fixed and chances don't change if you add more elements.
|
||||
* @param object
|
||||
* Object to add
|
||||
*/
|
||||
public void addRatio(double ratio, E object) {
|
||||
if (ratio <= 0 || ratio >= 1.0) {
|
||||
WarpDrive.logger.warn("Ratio isn't in (0, 1.0] bounds, skipping " + object);
|
||||
return;
|
||||
}
|
||||
|
||||
if (totalRatio + ratio > 1.0) {
|
||||
WarpDrive.logger.warn("Total ratio is greater than 1.0, skipping " + object);
|
||||
return;
|
||||
}
|
||||
totalRatio += ratio;
|
||||
ratioMap.put(totalRatio, object);
|
||||
list.add(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random object according weights and ratios
|
||||
*
|
||||
* @param random
|
||||
* @return Random object or null if there is no objects to pick.
|
||||
*/
|
||||
public E getRandomEntry(Random random) {
|
||||
double value = random.nextDouble();
|
||||
|
||||
if (value < totalRatio) { // hit ratio part of values
|
||||
return ratioMap.ceilingEntry(value).getValue();
|
||||
} else { // hit dynamic part of values, weighted ones
|
||||
double weight = (value - totalRatio) * totalWeight;
|
||||
return weightMap.ceilingEntry(weight).getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific object through its name
|
||||
*
|
||||
* @param name Exact name of the object
|
||||
* @return Named object or null if there is no object with that name
|
||||
*/
|
||||
public E getNamedEntry(final String name) {
|
||||
for(E object : list) {
|
||||
if (object.getName().equals(name)) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return All registered objects
|
||||
*/
|
||||
public ArrayList<E> elements() {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads object from given XML element and parses configurations for weighted pick.
|
||||
*
|
||||
* @param object
|
||||
* Object to load into
|
||||
* @param element
|
||||
* Element of an XML file
|
||||
* @throws InvalidXmlException
|
||||
*/
|
||||
public void loadFromXML(E object, Element element) throws InvalidXmlException {
|
||||
object.loadFromXmlElement(element);
|
||||
|
||||
try {
|
||||
String ratioStr = element.getAttribute("ratio");
|
||||
if (!ratioStr.isEmpty()) {
|
||||
double ratio = Double.parseDouble(ratioStr);
|
||||
addRatio(ratio, object);
|
||||
} else { // try weight
|
||||
try {
|
||||
int weight = 1;
|
||||
String stringWeight = element.getAttribute("weight");
|
||||
if (!stringWeight.isEmpty()) {
|
||||
weight = Integer.parseInt(stringWeight);
|
||||
weight = Math.max(1, weight);
|
||||
}
|
||||
|
||||
addWeight(weight, object);
|
||||
} catch (NumberFormatException exceptionWeight) {
|
||||
throw new InvalidXmlException("Weight must be an integer!");
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException exceptionRatio) {
|
||||
throw new InvalidXmlException("Ratio must be double!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,16 @@
|
|||
package cr0s.warpdrive.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
|
@ -13,44 +20,48 @@ import org.w3c.dom.NodeList;
|
|||
import cpw.mods.fml.common.Loader;
|
||||
import cr0s.warpdrive.WarpDrive;
|
||||
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
|
||||
|
||||
public class XmlPreprocessor {
|
||||
static boolean enableOuput = false;
|
||||
static int outputCount = 1;
|
||||
|
||||
/**
|
||||
* Will check the given element for a mod attribute and return a string of all the ones that are not loaded, separated by commas
|
||||
* Check the given element for a mod attribute and return a string of all the ones that are not loaded, separated by commas
|
||||
*
|
||||
* @param element
|
||||
* Element to check
|
||||
* @return A string, which is empty if all the mods are loaded.
|
||||
* @throws InvalidXmlException
|
||||
*/
|
||||
public static ModCheckResults checkModRequirements(Element element) {
|
||||
public static String checkModRequirements(Element element) {
|
||||
|
||||
ModCheckResults modErrors = new ModCheckResults();
|
||||
ModCheckResults modCheckResults = new ModCheckResults();
|
||||
|
||||
for (String mod : element.getAttribute("mods").split(",")) {
|
||||
|
||||
//TODO: add version check
|
||||
|
||||
|
||||
if (mod.isEmpty())
|
||||
if (mod.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mod.startsWith("!")) {
|
||||
if (Loader.isModLoaded(mod.substring(1))) {
|
||||
modCheckResults.addMod(mod, "loaded");
|
||||
}
|
||||
|
||||
if (Loader.isModLoaded(mod.substring(1)))
|
||||
modErrors.addMod(mod, "loaded");
|
||||
|
||||
} else if (!Loader.isModLoaded(mod))
|
||||
modErrors.addMod(mod, "not loaded");
|
||||
|
||||
} else if (!Loader.isModLoaded(mod)) {
|
||||
modCheckResults.addMod(mod, "not loaded");
|
||||
}
|
||||
}
|
||||
|
||||
return modErrors;
|
||||
return modCheckResults.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through every child node of the given node, and if it is an element and fails checkModRequirements() it is removed
|
||||
* Goes through every child node of the given node, and remove elements failing to checkModRequirements()
|
||||
*
|
||||
* @param base
|
||||
* @throws InvalidXmlException
|
||||
|
@ -64,11 +75,11 @@ public class XmlPreprocessor {
|
|||
|
||||
if (child instanceof Element) {
|
||||
Element elementChild = (Element) child;
|
||||
ModCheckResults res = checkModRequirements(elementChild);
|
||||
if (!res.isEmpty()) {
|
||||
String result = checkModRequirements(elementChild);
|
||||
if (!result.isEmpty()) {
|
||||
WarpDrive.logger.info("Skipping " + base.getNodeName() + "/" + elementChild.getNodeName()
|
||||
+ " " + elementChild.getAttribute("group") + elementChild.getAttribute("name") + elementChild.getAttribute("block")
|
||||
+ " due to " + res);
|
||||
+ " due to " + result);
|
||||
base.removeChild(child);
|
||||
} else {
|
||||
doModReqSanitation(child);
|
||||
|
@ -77,163 +88,171 @@ public class XmlPreprocessor {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Develop 'for' elements
|
||||
*
|
||||
* @param base
|
||||
* @throws InvalidXmlException
|
||||
*/
|
||||
public static void doLogicPreprocessing(Node root) throws InvalidXmlException {
|
||||
// process child first
|
||||
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")) {
|
||||
|
||||
// only process 'for' elements
|
||||
if (root.getNodeType() != Node.ELEMENT_NODE || !((Element) root).getTagName().equalsIgnoreCase("for")) {
|
||||
return;
|
||||
}
|
||||
Element elementFor = (Element) root;
|
||||
|
||||
// get variable name
|
||||
String variableName = elementFor.getAttribute("variable");
|
||||
if(variableName.isEmpty()) {
|
||||
throw new InvalidXmlException("A for tag must include a variable attribute!");
|
||||
}
|
||||
|
||||
// 'in' takes precedence over 'from' attribute
|
||||
if (elementFor.hasAttribute("in")) {
|
||||
String[] inOptions = elementFor.getAttribute("in").split(",");
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
// copy children with replaced variable
|
||||
for(String variableValue : inOptions) {
|
||||
NodeList allChildren = root.getChildNodes();
|
||||
for(int childIndex = 0; childIndex < allChildren.getLength(); childIndex ++) {
|
||||
Node copy = copyNodeAndReplaceVariable(allChildren.item(childIndex), variableName, variableValue);
|
||||
root.getParentNode().appendChild(copy);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
String fromStr = forTag.getAttribute("from");
|
||||
String toStr = forTag.getAttribute("to");
|
||||
}
|
||||
|
||||
} else {
|
||||
String stringFrom = elementFor.getAttribute("from");
|
||||
String stringTo = elementFor.getAttribute("to");
|
||||
|
||||
if (stringTo.isEmpty() || stringFrom.isEmpty()) {
|
||||
throw new InvalidXmlException("For element with no 'in' attribute requires both 'from' and 'to' attributes! " + variableName);
|
||||
}
|
||||
|
||||
int intFrom;
|
||||
int intTo;
|
||||
try {
|
||||
intFrom = Integer.parseInt(stringFrom);
|
||||
intTo = Integer.parseInt(stringTo);
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new InvalidXmlException(exception);
|
||||
}
|
||||
|
||||
// copy children with replaced variable
|
||||
for (int variableValue = intFrom; variableValue <= intTo; variableValue++) {
|
||||
NodeList allChildren = root.getChildNodes();
|
||||
for (int childIndex = 0; childIndex < allChildren.getLength(); childIndex++) {
|
||||
Node copy = copyNodeAndReplaceVariable(allChildren.item(childIndex), variableName, "" + variableValue);
|
||||
root.getParentNode().appendChild(copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Remove the old node
|
||||
root.getParentNode().removeChild(root);
|
||||
|
||||
if (enableOuput) {
|
||||
try {
|
||||
Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||
Result output = new StreamResult(new File("output" + outputCount + ".xml"));
|
||||
Source input = new DOMSource(root.getOwnerDocument());
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
transformer.transform(input, output);
|
||||
outputCount++;
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
private static Node copyNodeAndReplaceVariable(Node nodeOriginal, String variableName, String variableValue) {
|
||||
Node nodeCopy = nodeOriginal.cloneNode(true);
|
||||
replaceVariable(nodeCopy, "%" + variableName + "%", variableValue);
|
||||
|
||||
return copy;
|
||||
return nodeCopy;
|
||||
}
|
||||
|
||||
private static void replaceVar(Node root, String varName, String value) {
|
||||
|
||||
ArrayList<String> toRemove = new ArrayList<String>();
|
||||
ArrayList<Attr> toAdd = new ArrayList<Attr>();
|
||||
|
||||
if (root.getNodeType() == Node.ELEMENT_NODE) {
|
||||
|
||||
private static void replaceVariable(Node node, String keyword, String value) {
|
||||
ArrayList<String> nameToRemove = new ArrayList<String>();
|
||||
ArrayList<Attr> attrToAdd = new ArrayList<Attr>();
|
||||
|
||||
// process element's attributes first
|
||||
if (node.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);
|
||||
|
||||
// compute the changes
|
||||
NamedNodeMap attrs = node.getAttributes();
|
||||
for (int indexAttr = 0; indexAttr < attrs.getLength(); indexAttr++) {
|
||||
Attr oldAttr = (Attr) attrs.item(indexAttr);
|
||||
String oldName = oldAttr.getName();
|
||||
String newName = oldName.replace(keyword, value);
|
||||
|
||||
if (oldName.equals(newName)) {// same name, just adjust the value
|
||||
oldAttr.setValue(oldAttr.getValue().replace(keyword, value));
|
||||
|
||||
} else {// different name, needs to defer the add/remove
|
||||
nameToRemove.add(oldName);
|
||||
|
||||
Attr newAttr = oldAttr.getOwnerDocument().createAttribute(newName);
|
||||
newAttr.setValue(oldAttr.getValue().replace(keyword, value));
|
||||
attrToAdd.add(newAttr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Now do the adds and removals
|
||||
for (String attr : toRemove)
|
||||
|
||||
// then apply them
|
||||
for (String attr : nameToRemove) {
|
||||
attrs.removeNamedItem(attr);
|
||||
}
|
||||
|
||||
for (Attr attr : toAdd)
|
||||
for (Attr attr : attrToAdd) {
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// attributes are done, moving through child elements now
|
||||
NodeList children = node.getChildNodes();
|
||||
for (int childIndex = 0; childIndex < children.getLength(); childIndex++) {
|
||||
Node nodeChild = children.item(childIndex);
|
||||
|
||||
switch (nodeChild.getNodeType()) {
|
||||
case Node.ELEMENT_NODE: // recurse through elements
|
||||
replaceVariable(nodeChild, keyword, value);
|
||||
break;
|
||||
case Node.TEXT_NODE: // replace text in place
|
||||
nodeChild.setTextContent(nodeChild.getTextContent().replace(keyword, value));
|
||||
break;
|
||||
default: // ignore others
|
||||
// no operation
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ModCheckResults {
|
||||
|
||||
private TreeMap<String, String> mods;
|
||||
private TreeMap<String, String> modResults;
|
||||
|
||||
public ModCheckResults() {
|
||||
mods = new TreeMap<String, String>();
|
||||
modResults = new TreeMap<String, String>();
|
||||
}
|
||||
|
||||
public void addMod(String name, String error) {
|
||||
mods.put(name, error);
|
||||
modResults.put(name, error);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return mods.isEmpty();
|
||||
return modResults.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String string = (mods.size() > 1 ? "{" : "");
|
||||
String string = (modResults.size() > 1 ? "{" : "");
|
||||
boolean isFirst = true;
|
||||
for (Entry<String, String> entry : mods.entrySet()) {
|
||||
for (Entry<String, String> entry : modResults.entrySet()) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
|
@ -242,7 +261,7 @@ public class XmlPreprocessor {
|
|||
string += entry.getKey() + ": " + entry.getValue();
|
||||
}
|
||||
|
||||
return string + (mods.size() > 1 ? "}" : "");
|
||||
return string + (modResults.size() > 1 ? "}" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@ import org.w3c.dom.Document;
|
|||
import org.w3c.dom.Element;
|
||||
|
||||
public interface XmlRepresentable {
|
||||
|
||||
public void loadFromXmlElement(Element e) throws InvalidXmlException;
|
||||
|
||||
public void saveToXmlElement(Element e, Document d) throws InvalidXmlException;
|
||||
|
||||
public String getName();
|
||||
|
||||
public void loadFromXmlElement(Element element) throws InvalidXmlException;
|
||||
|
||||
public void saveToXmlElement(Element element, Document document) throws InvalidXmlException;
|
||||
}
|
||||
|
|
|
@ -15,16 +15,17 @@ import org.xml.sax.SAXException;
|
|||
|
||||
import cr0s.warpdrive.WarpDrive;
|
||||
import cr0s.warpdrive.config.InvalidXmlException;
|
||||
import cr0s.warpdrive.config.RandomCollection;
|
||||
import cr0s.warpdrive.config.WarpDriveConfig;
|
||||
import cr0s.warpdrive.config.XmlPreprocessor;
|
||||
import cr0s.warpdrive.config.XmlPreprocessor.ModCheckResults;
|
||||
|
||||
public class FillerManager {
|
||||
|
||||
private static TreeMap<String, FillerSet> fillerSets = new TreeMap<String, FillerSet>();
|
||||
private static TreeMap<String, FillerSet> fillerSetsByName = new TreeMap<String, FillerSet>();
|
||||
private static TreeMap<String, RandomCollection<FillerSet>> fillerSetsByGroup = new TreeMap<String, RandomCollection<FillerSet>>();
|
||||
|
||||
// Stores extra dependency information
|
||||
static TreeMap<FillerSet, ArrayList<String>> fillerSetsAdditions = new TreeMap<FillerSet, ArrayList<String>>();
|
||||
static TreeMap<FillerSet, ArrayList<String>> fillerSetsDependencies = new TreeMap<FillerSet, ArrayList<String>>();
|
||||
|
||||
/* TODO dead code?
|
||||
// FillerSets that are guaranteed to exist
|
||||
|
@ -52,7 +53,6 @@ public class FillerManager {
|
|||
|
||||
for(File file : files) {
|
||||
try {
|
||||
WarpDrive.logger.info("Loading filler data file " + file.getName() + "...");
|
||||
loadXmlFillerFile(file);
|
||||
} catch (Exception exception) {
|
||||
WarpDrive.logger.error("Error loading filler data file " + file.getName() + ": " + exception.getMessage());
|
||||
|
@ -63,44 +63,57 @@ public class FillerManager {
|
|||
}
|
||||
|
||||
private static void loadXmlFillerFile(File file) throws InvalidXmlException, SAXException, IOException {
|
||||
WarpDrive.logger.info("Loading filler data file " + file.getName());
|
||||
Document document = WarpDriveConfig.getXmlDocumentBuilder().parse(file);
|
||||
|
||||
Document base = WarpDriveConfig.getXmlDocumentBuilder().parse(file);
|
||||
|
||||
ModCheckResults res = XmlPreprocessor.checkModRequirements(base.getDocumentElement());
|
||||
|
||||
if (!res.isEmpty()) {
|
||||
WarpDrive.logger.info("Skippping filler data file " + file.getName() + " due to " + res);
|
||||
// pre-process the file
|
||||
String result = XmlPreprocessor.checkModRequirements(document.getDocumentElement());
|
||||
if (!result.isEmpty()) {
|
||||
WarpDrive.logger.info("Skipping filler data file " + file.getName() + " due to " + result);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove elements based on mod reqs sanitation
|
||||
XmlPreprocessor.doModReqSanitation(base);
|
||||
XmlPreprocessor.doLogicPreprocessing(base);
|
||||
XmlPreprocessor.doModReqSanitation(document);
|
||||
XmlPreprocessor.doLogicPreprocessing(document);
|
||||
|
||||
// Initially add FillerSets
|
||||
NodeList nodesFillerSet = base.getElementsByTagName("FillerSet");
|
||||
for (int i = 0; i < nodesFillerSet.getLength(); i++) {
|
||||
// only add FillerSets
|
||||
NodeList nodesFillerSet = document.getElementsByTagName("FillerSet");
|
||||
for (int fillerSetIndex = 0; fillerSetIndex < nodesFillerSet.getLength(); fillerSetIndex++) {
|
||||
|
||||
Element elementFillerSet = (Element) nodesFillerSet.item(i);
|
||||
Element elementFillerSet = (Element) nodesFillerSet.item(fillerSetIndex);
|
||||
|
||||
String group = elementFillerSet.getAttribute("group");
|
||||
if (group.isEmpty()) {
|
||||
throw new InvalidXmlException("FillerSet " + i + " is missing a group attribute!");
|
||||
throw new InvalidXmlException("FillerSet " + (fillerSetIndex + 1) + "/" + nodesFillerSet.getLength() + " is missing a group attribute!");
|
||||
}
|
||||
|
||||
FillerSet fillerSet = fillerSets.get(group);
|
||||
if (fillerSet == null) {
|
||||
fillerSet = new FillerSet(group);
|
||||
fillerSets.put(group, fillerSet);
|
||||
String name = elementFillerSet.getAttribute("name");
|
||||
if (name.isEmpty()) {
|
||||
throw new InvalidXmlException("FillerSet " + (fillerSetIndex + 1) + "/" + nodesFillerSet.getLength() + " is missing a name attribute!");
|
||||
}
|
||||
|
||||
WarpDrive.logger.info("- found FillerSet " + group + ":" + name);
|
||||
|
||||
FillerSet fillerSet = fillerSetsByName.get(name);
|
||||
if (fillerSet == null) {
|
||||
fillerSet = new FillerSet(group, name);
|
||||
fillerSetsByName.put(name, fillerSet);
|
||||
}
|
||||
|
||||
RandomCollection randomCollection = fillerSetsByGroup.get(group);
|
||||
if (randomCollection == null) {
|
||||
randomCollection = new RandomCollection<FillerSet>();
|
||||
fillerSetsByGroup.put(group, randomCollection);
|
||||
}
|
||||
randomCollection.loadFromXML(fillerSet, elementFillerSet);
|
||||
|
||||
if (elementFillerSet.hasAttribute("fillerSets")) {
|
||||
ArrayList<String> setUnresolvedDeps = fillerSetsAdditions.get(fillerSet);
|
||||
if (setUnresolvedDeps == null) {
|
||||
setUnresolvedDeps = new ArrayList<String>();
|
||||
fillerSetsAdditions.put(fillerSet, setUnresolvedDeps);
|
||||
ArrayList<String> dependencies = fillerSetsDependencies.get(fillerSet);
|
||||
if (dependencies == null) {
|
||||
dependencies = new ArrayList<String>();
|
||||
fillerSetsDependencies.put(fillerSet, dependencies);
|
||||
}
|
||||
setUnresolvedDeps.addAll(Arrays.asList(elementFillerSet.getAttribute("import").split(",")));
|
||||
dependencies.addAll(Arrays.asList(elementFillerSet.getAttribute("fillerSets").split(",")));
|
||||
}
|
||||
|
||||
fillerSet.loadFromXmlElement(elementFillerSet);
|
||||
|
@ -108,47 +121,48 @@ public class FillerManager {
|
|||
}
|
||||
|
||||
public static void finishLoading() {
|
||||
// import fillerSets into each others
|
||||
propagateFillerSets();
|
||||
|
||||
while (!fillerSetsAdditions.isEmpty()) {
|
||||
attemptDependencyFilling(fillerSetsAdditions);
|
||||
}
|
||||
|
||||
// When everything is done, finalize
|
||||
for (FillerSet fillerSet : fillerSets.values()) {
|
||||
// compute fillerSets randomization tables
|
||||
for (FillerSet fillerSet : fillerSetsByName.values()) {
|
||||
fillerSet.finishContruction();
|
||||
}
|
||||
|
||||
// compute groups randomization tables
|
||||
for (RandomCollection randomCollection : fillerSetsByGroup.values()) {
|
||||
// randomCollection.finishContruction();
|
||||
}
|
||||
}
|
||||
|
||||
private static void attemptDependencyFilling(TreeMap<FillerSet, ArrayList<String>> fillerSetsDeps) {
|
||||
|
||||
ArrayList<FillerSet> toRemove = new ArrayList<FillerSet>();
|
||||
|
||||
for (Entry<FillerSet, ArrayList<String>> entry : fillerSetsDeps.entrySet()) {
|
||||
private static void propagateFillerSets() {
|
||||
while (!fillerSetsDependencies.isEmpty()) {
|
||||
TreeMap<FillerSet, ArrayList<String>> fillerSetsLeftToImport = new TreeMap<FillerSet, ArrayList<String>>();
|
||||
|
||||
for (String dep : entry.getValue()) {
|
||||
|
||||
if (!fillerSets.containsKey(dep)) {
|
||||
|
||||
WarpDrive.logger.error("Skipping FillerSet " + entry.getKey() + " due to missing dependency " + dep);
|
||||
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 (Entry<FillerSet, ArrayList<String>> entry : fillerSetsDependencies.entrySet()) {
|
||||
ArrayList<String> newDependencies = new ArrayList();
|
||||
for (String dependency : entry.getValue()) {
|
||||
if (!fillerSetsByName.containsKey(dependency)) {
|
||||
WarpDrive.logger.error("Ignoring FillerSet " + dependency + " dependency in FillerSet " + entry.getKey());
|
||||
|
||||
} else if (fillerSetsDependencies.containsKey(fillerSetsByName.get(dependency))) {
|
||||
// skip until it is loaded
|
||||
newDependencies.add(dependency);
|
||||
|
||||
} else {
|
||||
entry.getKey().loadFrom(fillerSetsByName.get(dependency));
|
||||
}
|
||||
}
|
||||
if (!newDependencies.isEmpty()) {
|
||||
fillerSetsLeftToImport.put(entry.getKey(), newDependencies);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (FillerSet set : toRemove) {
|
||||
fillerSetsDeps.remove(set);
|
||||
|
||||
fillerSetsDependencies = fillerSetsLeftToImport;
|
||||
}
|
||||
}
|
||||
|
||||
public static FillerSet getFillerSet(String name) {
|
||||
return fillerSets.get(name);
|
||||
public static boolean doesFillerSetExist(String groupOrName) {
|
||||
return fillerSetsByName.containsKey(groupOrName) || fillerSetsByName.containsKey(groupOrName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,51 +20,57 @@ import net.minecraft.init.Blocks;
|
|||
*
|
||||
*/
|
||||
public class FillerSet implements XmlRepresentable, Comparable {
|
||||
|
||||
private MetaBlock[] weightedFillerBlocks;
|
||||
private FillerFactory factory;
|
||||
protected String group;
|
||||
protected String name;
|
||||
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public FillerSet(MetaBlock[] blocks) {
|
||||
weightedFillerBlocks = blocks;
|
||||
}
|
||||
|
||||
public FillerSet(String name) {
|
||||
|
||||
|
||||
public FillerSet(final String group, final String name) {
|
||||
|
||||
this.group = group;
|
||||
this.name = name;
|
||||
|
||||
|
||||
weightedFillerBlocks = new MetaBlock[1];
|
||||
factory = new FillerFactory();
|
||||
}
|
||||
|
||||
|
||||
public MetaBlock getRandomBlock(Random rand) {
|
||||
return weightedFillerBlocks[rand.nextInt(weightedFillerBlocks.length)];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void loadFromXmlElement(Element element) throws InvalidXmlException {
|
||||
|
||||
|
||||
NodeList fillers = element.getElementsByTagName("filler");
|
||||
for (int i = 0; i < fillers.getLength(); i++) {
|
||||
|
||||
|
||||
Element filler = (Element) fillers.item(i);
|
||||
|
||||
|
||||
// Check there is a block name
|
||||
if (!filler.hasAttribute("block")) {
|
||||
throw new InvalidXmlException("Filler " + filler + " is missing a block tag!");
|
||||
}
|
||||
|
||||
|
||||
String blockName = filler.getAttribute("block");
|
||||
Block block = Block.getBlockFromName(blockName);
|
||||
if (block == null) {
|
||||
WarpDrive.logger.warn("Skipping missing block " + blockName);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Get metadata attribute, defaults to 0
|
||||
int intMetadata = 0;
|
||||
String stringMetadata = filler.getAttribute("metadata");
|
||||
|
@ -75,54 +81,58 @@ public class FillerSet implements XmlRepresentable, Comparable {
|
|||
throw new InvalidXmlException("Invalid metadata for block " + blockName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boolean hasWeightOrRatio = false;
|
||||
|
||||
|
||||
// It is intentional that a filler could have both a ratio and a weight
|
||||
|
||||
|
||||
// Check for a weight and add it to the factory
|
||||
String stringWeight = filler.getAttribute("weight");
|
||||
int weight;
|
||||
|
||||
|
||||
if (!stringWeight.isEmpty()) {
|
||||
hasWeightOrRatio = true;
|
||||
|
||||
|
||||
try {
|
||||
weight = Integer.parseInt(stringWeight);
|
||||
|
||||
|
||||
factory.addWeightedBlock(block, intMetadata, weight);
|
||||
|
||||
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new InvalidXmlException("Invalid weight for block " + blockName);
|
||||
} catch (IllegalArgumentException exception) {
|
||||
throw new InvalidXmlException(exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for a ratio attribute, and add it to the factory
|
||||
String stringRatio = filler.getAttribute("ratio");
|
||||
if (!stringRatio.isEmpty()) {
|
||||
hasWeightOrRatio = true;
|
||||
|
||||
|
||||
try {
|
||||
factory.addRatioBlock(block, intMetadata, stringRatio);
|
||||
|
||||
|
||||
} catch (IllegalArgumentException exception) {
|
||||
throw new InvalidXmlException(exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!hasWeightOrRatio) {
|
||||
throw new InvalidXmlException("No ratio nor weight defined for block " + blockName + " " + stringMetadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Not implemented
|
||||
**/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void saveToXmlElement(Element element, Document document) throws InvalidXmlException {
|
||||
throw new InvalidXmlException("Not supported");
|
||||
throw new InvalidXmlException("Not implemented");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Uses the data that has been loaded thus far to construct the array in order to make the FillerSet functional. Must be called before calling getRandomBlock()
|
||||
*
|
||||
|
@ -131,27 +141,27 @@ public class FillerSet implements XmlRepresentable, Comparable {
|
|||
public void finishContruction() {
|
||||
WarpDrive.logger.info("Finishing construction of " + name);
|
||||
weightedFillerBlocks = factory.constructWeightedMetaBlockList();
|
||||
|
||||
//For some reason some entries are null, so replace them with air
|
||||
|
||||
//For some reason some entries are null, so replace them with air FIXME
|
||||
for (int i = 0; i < weightedFillerBlocks.length; i++) {
|
||||
if (weightedFillerBlocks[i] == null)
|
||||
if (weightedFillerBlocks[i] == null) {
|
||||
weightedFillerBlocks[i] = MetaBlock.getMetaBlock(Blocks.air, 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
factory = null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(Object object) {
|
||||
return name.compareTo(((FillerSet) object).name);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the blocks from the given fillerSet into this one. Must be pre-finishConstruction()
|
||||
*
|
||||
|
|
|
@ -8,128 +8,132 @@ import org.w3c.dom.Element;
|
|||
import cr0s.warpdrive.WarpDrive;
|
||||
import cr0s.warpdrive.config.InvalidXmlException;
|
||||
import cr0s.warpdrive.config.MetaBlock;
|
||||
import cr0s.warpdrive.data.VectorI;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class Asteroid extends Orb {
|
||||
|
||||
private static final int MIN_RADIUS = 1;
|
||||
private static final int CORE_MAX_TRIES = 10;
|
||||
|
||||
private Block coreBlock;
|
||||
|
||||
private int maxCoreSize, minCoreSize;
|
||||
private double coreRad;
|
||||
|
||||
public Asteroid() {
|
||||
super(0); //Diameter not relevant
|
||||
private int maxCoreCount;
|
||||
private int minCoreCount;
|
||||
private double relativeCoreRadius;
|
||||
|
||||
public Asteroid(final String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void loadFromXmlElement(Element e) throws InvalidXmlException {
|
||||
|
||||
super.loadFromXmlElement(e);
|
||||
|
||||
String coreBlockName = e.getAttribute("coreBlock");
|
||||
if (coreBlockName.isEmpty())
|
||||
throw new InvalidXmlException("Asteroid is missing a coreBlock!");
|
||||
|
||||
public void loadFromXmlElement(Element element) throws InvalidXmlException {
|
||||
super.loadFromXmlElement(element);
|
||||
|
||||
String coreBlockName = element.getAttribute("coreBlock");
|
||||
if (coreBlockName.isEmpty()) {
|
||||
throw new InvalidXmlException("Asteroid " + name + " is missing a coreBlock!");
|
||||
}
|
||||
|
||||
coreBlock = Block.getBlockFromName(coreBlockName);
|
||||
if (coreBlock == null)
|
||||
throw new InvalidXmlException("Asteroid coreBlock doesnt exist!");
|
||||
|
||||
try {
|
||||
|
||||
maxCoreSize = Integer.parseInt(e.getAttribute("maxCoreSize"));
|
||||
minCoreSize = Integer.parseInt(e.getAttribute("minCoreSize"));
|
||||
|
||||
} catch (NumberFormatException gdbg) {
|
||||
throw new InvalidXmlException("Asteroid core size dimensions are NaN!");
|
||||
if (coreBlock == null) {
|
||||
throw new InvalidXmlException("Asteroid " + name + " has an invalid/missing coreBlock " + coreBlockName);
|
||||
}
|
||||
|
||||
try {
|
||||
String coreRadStr = e.getAttribute("coreRad");
|
||||
if(coreRadStr.isEmpty()) {
|
||||
coreRad = 0.1;
|
||||
minCoreCount = Integer.parseInt(element.getAttribute("minCoreCount"));
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new InvalidXmlException("Asteroid " + name + " has an invalid minCoreCount " + element.getAttribute("minCoreCount") + ", expecting an integer");
|
||||
}
|
||||
|
||||
if (minCoreCount < 1) {
|
||||
throw new InvalidXmlException("Asteroid " + name + " has an invalid minCoreCount " + minCoreCount + ", expecting greater then 0");
|
||||
}
|
||||
|
||||
try {
|
||||
maxCoreCount = Integer.parseInt(element.getAttribute("maxCoreCount"));
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new InvalidXmlException("Asteroid " + name + " has an invalid maxCoreCount " + element.getAttribute("maxCoreCount") + ", expecting an integer");
|
||||
}
|
||||
|
||||
if (maxCoreCount < minCoreCount) {
|
||||
throw new InvalidXmlException("Asteroid " + name + " has an invalid maxCoreCount " + maxCoreCount + ", expecting greater than or equal to minCoreCount " + minCoreCount);
|
||||
}
|
||||
|
||||
try {
|
||||
String stringCoreRad = element.getAttribute("relativeCoreRadius");
|
||||
if (stringCoreRad.isEmpty()) {
|
||||
relativeCoreRadius = 0.1;
|
||||
} else {
|
||||
coreRad = Double.parseDouble(e.getAttribute("coreRad"));
|
||||
relativeCoreRadius = Double.parseDouble(element.getAttribute("relativeCoreRadius"));
|
||||
}
|
||||
} catch (NumberFormatException gdbg) {
|
||||
throw new InvalidXmlException("Asteroid core rad must be double!");
|
||||
throw new InvalidXmlException("Asteroid " + name + " has an invalid relativeCoreRadius " + element.getAttribute("relativeCoreRadius") + ", expecting a double");
|
||||
}
|
||||
|
||||
if (relativeCoreRadius < 0.0D || relativeCoreRadius > 1.0D) {
|
||||
throw new InvalidXmlException("Asteroid " + name + " has an invalid relativeCoreRadius " + relativeCoreRadius + ", expecting a value between 0.0 and 1.0 included");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generate(World world, Random rand, int x, int y, int z) {
|
||||
int randRadius = MIN_RADIUS + rand.nextInt(Math.max(1, getRadius() - MIN_RADIUS));
|
||||
int numberCoreBlocks = minCoreSize + rand.nextInt(Math.max(1, maxCoreSize - minCoreSize));
|
||||
|
||||
WarpDrive.logger.info("Asteroid generation: radius=" + randRadius + ", numCoreBlocks=" + numberCoreBlocks + ", coreRad=" + coreRad);
|
||||
|
||||
//Use this to generate a abstract form for the core.
|
||||
ArrayList<Location> coreLocations = generateCore(world, rand, x, y, z, numberCoreBlocks, coreBlock, numberCoreBlocks, randRadius);
|
||||
|
||||
for (Location coreLocation: coreLocations) {
|
||||
// Calculate mininum distance to borders of generation area
|
||||
int maxRadX = Math.min(x+randRadius-coreLocation.x, coreLocation.x - (x - randRadius));
|
||||
int maxRadY = Math.min(y+randRadius-coreLocation.y, coreLocation.y - (y - randRadius));
|
||||
int maxRadZ = Math.min(z+randRadius-coreLocation.z, coreLocation.z - (z - randRadius));
|
||||
int maxLocalRadius = Math.min(maxRadX, Math.min(maxRadY, maxRadZ));
|
||||
|
||||
// Generate shell
|
||||
addShell(world, rand, coreLocation, maxLocalRadius);
|
||||
public boolean generate(World world, Random random, int x, int y, int z) {
|
||||
int[] thicknesses = randomize(random);
|
||||
int totalThickness = 0;
|
||||
for (int thickness : thicknesses) {
|
||||
totalThickness += thickness;
|
||||
}
|
||||
|
||||
int coreBlocksCount = minCoreCount + ((maxCoreCount > minCoreCount) ? random.nextInt(maxCoreCount - minCoreCount) : 0);
|
||||
|
||||
WarpDrive.logger.info("Generating asteroid " + name + " as radius " + totalThickness + " coreBlocksCount " + coreBlocksCount + " coreRad " + relativeCoreRadius);
|
||||
|
||||
// use this to generate an abstract form for the core.
|
||||
double coreRadius = relativeCoreRadius * totalThickness;
|
||||
ArrayList<VectorI> coreLocations = generateCore(world, random, x, y, z, coreBlocksCount, coreBlock, coreBlocksCount, coreRadius);
|
||||
|
||||
for (VectorI coreLocation: coreLocations) {
|
||||
// Calculate minimum distance to borders of generation area
|
||||
int maxRadX = totalThickness - Math.abs(x - coreLocation.x);
|
||||
int maxRadY = totalThickness - Math.abs(y - coreLocation.y);
|
||||
int maxRadZ = totalThickness - Math.abs(z - coreLocation.z);
|
||||
int maxLocalRadius = Math.max(maxRadX, Math.max(maxRadY, maxRadZ));
|
||||
|
||||
// Generate shell
|
||||
addShell(thicknesses, world, coreLocation, maxLocalRadius);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a shell sphere around given core location.
|
||||
*
|
||||
* @param thicknesses Random generator
|
||||
* @param world World to place shell
|
||||
* @param rand Random generator
|
||||
* @param l Location of core block
|
||||
* @param location Location of core block
|
||||
* @param maxRad Maximum radius of asteroid
|
||||
*/
|
||||
private void addShell(World world, Random rand, Location l, int maxRad) {
|
||||
//int rad = MIN_RADIUS + rand.nextInt(Math.max(1, maxRad - MIN_RADIUS));
|
||||
int rad = maxRad;
|
||||
|
||||
// Iterate all blocks withing cube with side 2*rad
|
||||
for(int x = l.x - rad; x <= l.x + rad; ++x) {
|
||||
for(int y = l.y - rad; y <= l.y + rad; ++y) {
|
||||
for(int z = l.z - rad; z <= l.z + rad; ++z) {
|
||||
private void addShell(int[] thicknesses, World world, VectorI location, int radius) {
|
||||
// iterate all blocks within cube with side 2 * radius
|
||||
for(int x = location.x - radius; x <= location.x + radius; x++) {
|
||||
int dX2 = (x - location.x) * (x - location.x);
|
||||
for(int y = location.y - radius; y <= location.y + radius; y++) {
|
||||
int dX2Y2 = dX2 + (y - location.y) * (y - location.y);
|
||||
for(int z = location.z - radius; z <= location.z + radius; z++) {
|
||||
// current radius
|
||||
int r = (int)Math.round(Math.sqrt((l.x - x)*(l.x - x) + (l.y - y)*(l.y - y) + (l.z - z)*(l.z - z)));
|
||||
int range = (int)Math.round(Math.sqrt(dX2Y2 + (location.z - z) * (location.z - z)));
|
||||
|
||||
// if inside radius
|
||||
if(r <= rad && isBlockEmpty(world, x, y, z)) {
|
||||
OrbShell shell = getShellForRadius(r);
|
||||
MetaBlock blType = shell.getRandomBlock(rand);
|
||||
world.setBlock(x, y, z, blType.block, blType.metadata, 0);
|
||||
if(range <= radius && isReplaceableOreGen(world, x, y, z)) {
|
||||
OrbShell shell = getShellForRadius(thicknesses, range);
|
||||
MetaBlock metaBlock = shell.getRandomBlock(world.rand);
|
||||
world.setBlock(x, y, z, metaBlock.block, metaBlock.metadata, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a single point in space
|
||||
*
|
||||
*/
|
||||
private class Location {
|
||||
|
||||
public int x, y, z;
|
||||
|
||||
public Location(int x, int y, int z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if given coordinate empty (air in terms of MC).
|
||||
* @param world
|
||||
|
@ -138,7 +142,7 @@ public class Asteroid extends Orb {
|
|||
* @param z
|
||||
* @return
|
||||
*/
|
||||
private static boolean isBlockEmpty(World world, int x, int y, int z) {
|
||||
private static boolean isReplaceableOreGen(World world, int x, int y, int z) {
|
||||
return world.getBlock(x, y, z).isReplaceableOreGen(world, x, y, z, Blocks.air);
|
||||
}
|
||||
|
||||
|
@ -155,41 +159,36 @@ public class Asteroid extends Orb {
|
|||
* @param numberOfBlocks - number of core blocks to place
|
||||
* @param block - type of block to place
|
||||
* @param metadata - metadata of bloeck to place
|
||||
* @param maxRange - max radius of asteroid
|
||||
* @param coreRadius - max radius of asteroid
|
||||
* @return List of placed locations of cores
|
||||
*/
|
||||
private ArrayList<Location> generateCore(World world, Random rand, int x, int y, int z, int numberOfBlocks, Block block, int metadata,
|
||||
int maxRange) {
|
||||
|
||||
ArrayList<Location> addedBlocks = new ArrayList<Location>();
|
||||
int coreRange = (int)Math.round(coreRad * maxRange);
|
||||
int maxX = x + coreRange;
|
||||
int minX = x - coreRange;
|
||||
int maxY = y + coreRange;
|
||||
int minY = y - coreRange;
|
||||
int maxZ = z + coreRange;
|
||||
int minZ = z - coreRange;
|
||||
private ArrayList<VectorI> generateCore(World world, Random rand, int x, int y, int z,
|
||||
int numberOfBlocks, Block block, int metadata, double coreRadius) {
|
||||
ArrayList<VectorI> addedBlocks = new ArrayList<VectorI>();
|
||||
int coreDiameter = Math.max(1, (int)Math.round(2 * coreRadius));
|
||||
int xMin = x - (int)Math.round(coreRadius);
|
||||
int yMin = y - (int)Math.round(coreRadius);
|
||||
int zMin = z - (int)Math.round(coreRadius);
|
||||
|
||||
for (int i = 0; i < numberOfBlocks; ++i) {
|
||||
for (int coreBlockIndex = 0; coreBlockIndex < numberOfBlocks; coreBlockIndex++) {
|
||||
int curX = x;
|
||||
int curY = y;
|
||||
int curZ = z;
|
||||
boolean stopWalk = false;
|
||||
boolean found = false;
|
||||
|
||||
for(int step = 0; step <= CORE_MAX_TRIES && !stopWalk; ++step) {
|
||||
curX = rand.nextInt(Math.max(1, maxX - minX)) + minX;
|
||||
curY = rand.nextInt(Math.max(1, maxY - minY)) + minY;
|
||||
curZ = rand.nextInt(Math.max(1, maxZ - minZ)) + minZ;
|
||||
for(int step = 0; step < CORE_MAX_TRIES && !found; step++) {
|
||||
curX = xMin + rand.nextInt(coreDiameter);
|
||||
curY = yMin + rand.nextInt(coreDiameter);
|
||||
curZ = zMin + rand.nextInt(coreDiameter);
|
||||
|
||||
if (isBlockEmpty(world, curX, curY, curZ)) {
|
||||
if (isReplaceableOreGen(world, curX, curY, curZ)) {
|
||||
world.setBlock(curX, curY, curZ, block, metadata, 2);
|
||||
addedBlocks.add(new Location(curX, curY, curZ));
|
||||
stopWalk = true;
|
||||
addedBlocks.add(new VectorI(curX, curY, curZ));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return addedBlocks;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,31 +6,29 @@ package cr0s.warpdrive.config.structures;
|
|||
import net.minecraft.world.gen.feature.WorldGenerator;
|
||||
|
||||
/**
|
||||
* @author Francesco
|
||||
* @author Francesco, LemADEC
|
||||
*
|
||||
*/
|
||||
public abstract class DeployableStructure extends WorldGenerator {
|
||||
protected String name;
|
||||
protected int sizeX;
|
||||
protected int sizeY;
|
||||
protected int sizeZ;
|
||||
|
||||
protected int height;
|
||||
protected int width;
|
||||
protected int length;
|
||||
|
||||
public DeployableStructure(int height, int width, int length) {
|
||||
this.height = height;
|
||||
this.width = width;
|
||||
this.length = length;
|
||||
public DeployableStructure(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
|
||||
public void setDimensions(final int sizeX, final int sizeY, final int sizeZ) {
|
||||
this.sizeX = sizeX;
|
||||
this.sizeY = sizeY;
|
||||
this.sizeZ = sizeZ;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
|
||||
public void setRadius(final int radius) {
|
||||
sizeX = radius * 2;
|
||||
sizeY = radius * 2;
|
||||
sizeZ = radius * 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,164 +15,142 @@ import cr0s.warpdrive.config.XmlRepresentable;
|
|||
import cr0s.warpdrive.config.filler.FillerManager;
|
||||
import cr0s.warpdrive.config.filler.FillerSet;
|
||||
import cr0s.warpdrive.world.EntitySphereGen;
|
||||
import cr0s.warpdrive.world.EntityStarCore;
|
||||
|
||||
public abstract class Orb extends DeployableStructure implements XmlRepresentable {
|
||||
|
||||
private OrbShell[] shellRelative;
|
||||
// private ArrayList<OrbShell> shells;
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* @return the radius
|
||||
*/
|
||||
public int getRadius() {
|
||||
return super.height / 2;
|
||||
|
||||
private OrbShell[] orbShells;
|
||||
protected boolean hasStarCore = false;
|
||||
private ArrayList<String> fillerSetGroupOrNames = new ArrayList<String>();
|
||||
|
||||
public Orb(final String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param radius the radius to set
|
||||
*/
|
||||
public void setRadius(int radius) {
|
||||
|
||||
super.height = radius * 2;
|
||||
super.length = radius * 2;
|
||||
super.width = radius * 2;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Orb(int radius) {
|
||||
super(radius * 2, radius * 2, radius * 2);
|
||||
|
||||
setRadius(radius);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void loadFromXmlElement(Element element) throws InvalidXmlException {
|
||||
|
||||
name = element.getAttribute("name");
|
||||
|
||||
ArrayList<OrbShell> newShells = new ArrayList<OrbShell>();
|
||||
int totalThickness = 0;
|
||||
|
||||
NodeList shells = element.getElementsByTagName("shell");
|
||||
for (int i = 0; i < shells.getLength(); i++) {
|
||||
Element elementShell = (Element) shells.item(i);
|
||||
|
||||
OrbShell shell = new OrbShell();
|
||||
shell.loadFromXmlElement(elementShell);
|
||||
shell.finishContruction();
|
||||
totalThickness += shell.thickness;
|
||||
newShells.add(shell);
|
||||
|
||||
int maxThickness = 0;
|
||||
|
||||
NodeList nodeListShells = element.getElementsByTagName("shell");
|
||||
orbShells = new OrbShell[nodeListShells.getLength()];
|
||||
for (int shellIndex = 0; shellIndex < nodeListShells.getLength(); shellIndex++) {
|
||||
Element elementShell = (Element) nodeListShells.item(shellIndex);
|
||||
String orbShellName = element.getAttribute("name");
|
||||
|
||||
orbShells[shellIndex] = new OrbShell(name, orbShellName);
|
||||
orbShells[shellIndex].loadFromXmlElement(elementShell);
|
||||
orbShells[shellIndex].finishContruction();
|
||||
maxThickness += orbShells[shellIndex].maxThickness;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
shellRelative = new OrbShell[totalThickness];
|
||||
|
||||
for (OrbShell shell : newShells) {
|
||||
|
||||
for (int i = 0; i < shell.thickness; i++)
|
||||
shellRelative[index++] = shell;
|
||||
}
|
||||
|
||||
setRadius(totalThickness - 1);
|
||||
|
||||
setRadius(maxThickness - 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Not implemented
|
||||
**/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void saveToXmlElement(Element element, Document document) {
|
||||
/* TODO: dead code?
|
||||
for (OrbShell shell : shells) {
|
||||
Element tmp = document.createElement("shell");
|
||||
shell.saveToXmlElement(tmp, document);
|
||||
element.appendChild(tmp);
|
||||
}
|
||||
/**/
|
||||
public void saveToXmlElement(Element element, Document document) throws InvalidXmlException {
|
||||
throw new InvalidXmlException("Not implemented");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean generate(World world, Random random, int x, int y, int z) {
|
||||
EntitySphereGen entitySphereGen = new EntitySphereGen(world, x, y, z, getRadius(), this, true);
|
||||
int[] thicknesses = randomize(random);
|
||||
int totalThickness = 0;
|
||||
for (int thickness : thicknesses) {
|
||||
totalThickness += thickness;
|
||||
}
|
||||
EntitySphereGen entitySphereGen = new EntitySphereGen(world, x, y, z, this, thicknesses, totalThickness, true);
|
||||
world.spawnEntityInWorld(entitySphereGen);
|
||||
if (hasStarCore) {
|
||||
return world.spawnEntityInWorld(new EntityStarCore(world, x, y, z, totalThickness));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @Deprecated pending addition of variables offsets in structure XML attributes
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean generate(World world, Random random, int x, int y, int z, final int radius) {
|
||||
EntitySphereGen entitySphereGen = new EntitySphereGen(world, x, y, z, radius, this, true);
|
||||
EntitySphereGen entitySphereGen = new EntitySphereGen(world, x, y, z, this, null, radius, true);
|
||||
world.spawnEntityInWorld(entitySphereGen);
|
||||
return false;
|
||||
}
|
||||
|
||||
public OrbShell getShellForRadius(int r) {
|
||||
return shellRelative[r];
|
||||
|
||||
public int[] randomize(Random random) {
|
||||
int[] thicknesses = new int[orbShells.length];
|
||||
for(int orbShellIndex = 0; orbShellIndex < orbShells.length; orbShellIndex++) {
|
||||
OrbShell orbShell = orbShells[orbShellIndex];
|
||||
thicknesses[orbShellIndex] = orbShell.minThickness
|
||||
+ ((orbShell.maxThickness - orbShell.minThickness > 0) ? random.nextInt(orbShell.maxThickness - orbShell.minThickness) : 0);
|
||||
}
|
||||
return thicknesses;
|
||||
}
|
||||
|
||||
|
||||
public OrbShell getShellForRadius(final int[] thicknesses, final int range) {
|
||||
int cumulatedRange = 0;
|
||||
for (int shellIndex = 0; shellIndex < orbShells.length; shellIndex++) {
|
||||
cumulatedRange += thicknesses[shellIndex];
|
||||
if (range <= cumulatedRange) {
|
||||
return orbShells[shellIndex];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public class OrbShell extends FillerSet {
|
||||
|
||||
private int thickness;
|
||||
|
||||
/**
|
||||
* @return the thickness
|
||||
*/
|
||||
public int getThickness() {
|
||||
return thickness;
|
||||
private String parentName;
|
||||
private int minThickness;
|
||||
private int maxThickness;
|
||||
|
||||
public OrbShell(String parentName, String name) {
|
||||
super(null, name);
|
||||
this.parentName = parentName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param thickness
|
||||
* the thickness to set
|
||||
*/
|
||||
public void setThickness(int thickness) {
|
||||
this.thickness = thickness;
|
||||
}
|
||||
|
||||
public OrbShell() {
|
||||
|
||||
super("");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void loadFromXmlElement(Element element) throws InvalidXmlException {
|
||||
|
||||
WarpDrive.logger.info("Loading shell " + element.getAttribute("name"));
|
||||
name = element.getAttribute("name");
|
||||
|
||||
|
||||
super.loadFromXmlElement(element);
|
||||
|
||||
|
||||
if (element.hasAttribute("fillerSets")) {
|
||||
String[] imports = element.getAttribute("fillerSets").split(",");
|
||||
|
||||
for (String imp : imports) {
|
||||
FillerSet fillSet = FillerManager.getFillerSet(imp);
|
||||
|
||||
if (fillSet == null)
|
||||
throw new InvalidXmlException("Shell loading tries to import a non-existant fillerSet!");
|
||||
|
||||
super.loadFrom(fillSet);
|
||||
String[] allFillerSetGroupOrNames = element.getAttribute("fillerSets").split(",");
|
||||
|
||||
for (String fillerSetGroupOrName : allFillerSetGroupOrNames) {
|
||||
if (!FillerManager.doesFillerSetExist(fillerSetGroupOrName)) {
|
||||
WarpDrive.logger.warn("Skipping missing FillerSet " + fillerSetGroupOrName + " in shell " + name);
|
||||
} else {
|
||||
fillerSetGroupOrNames.add(fillerSetGroupOrName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
thickness = Integer.parseInt(element.getAttribute("maxThickness"));
|
||||
minThickness = Integer.parseInt(element.getAttribute("minThickness"));
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new InvalidXmlException("MaxThickness is not valid!");
|
||||
throw new InvalidXmlException("Invalid minThickness in shell " + name + " of orb " + parentName);
|
||||
}
|
||||
|
||||
try {
|
||||
maxThickness = Integer.parseInt(element.getAttribute("maxThickness"));
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new InvalidXmlException("Invalid maxThickness in shell " + name + " of orb " + parentName);
|
||||
}
|
||||
|
||||
if (maxThickness < minThickness) {
|
||||
throw new InvalidXmlException("Invalid maxThickness " + maxThickness + " lower than minThickness " + minThickness + " in shell " + name + " of orb " + parentName);
|
||||
}
|
||||
|
||||
//TODO: Implement random thickness
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveToXmlElement(Element e, Document d) {
|
||||
//Not needed
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package cr0s.warpdrive.config.structures;
|
||||
|
||||
public class Planetoid extends Orb {
|
||||
|
||||
public Planetoid(int diameter) {
|
||||
super(diameter);
|
||||
// TODO Auto-generated constructor stub
|
||||
public Planetoid(final String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ import net.minecraft.world.World;
|
|||
|
||||
public class SchematicStructure extends DeployableStructure {
|
||||
|
||||
public SchematicStructure(int height, int width, int length) {
|
||||
super(height, width, length);
|
||||
public SchematicStructure(final String name) {
|
||||
super(name);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,9 @@
|
|||
package cr0s.warpdrive.config.structures;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
import cr0s.warpdrive.world.EntityStarCore;
|
||||
|
||||
public class Star extends Orb {
|
||||
|
||||
public Star(int diameter) {
|
||||
super(diameter);
|
||||
public Star(final String name) {
|
||||
super(name);
|
||||
hasStarCore = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generate(World p_76484_1_, Random p_76484_2_, int p_76484_3_, int p_76484_4_, int p_76484_5_) {
|
||||
boolean success = super.generate(p_76484_1_, p_76484_2_, p_76484_3_, p_76484_4_, p_76484_5_);
|
||||
|
||||
if (success)
|
||||
return placeStarCore(p_76484_1_, p_76484_3_, p_76484_4_, p_76484_5_, super.getHeight() / 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean placeStarCore(World world, int x, int y, int z, int radius) {
|
||||
return world.spawnEntityInWorld(new EntityStarCore(world, x, y, z, radius));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,10 +3,7 @@ package cr0s.warpdrive.config.structures;
|
|||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Random;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
@ -15,27 +12,25 @@ import org.xml.sax.SAXException;
|
|||
|
||||
import cr0s.warpdrive.WarpDrive;
|
||||
import cr0s.warpdrive.config.InvalidXmlException;
|
||||
import cr0s.warpdrive.config.RandomCollection;
|
||||
import cr0s.warpdrive.config.WarpDriveConfig;
|
||||
import cr0s.warpdrive.config.XmlPreprocessor;
|
||||
import cr0s.warpdrive.config.XmlPreprocessor.ModCheckResults;
|
||||
import cr0s.warpdrive.config.XmlRepresentable;
|
||||
|
||||
|
||||
public class StructureManager {
|
||||
public static final String GROUP_STARS = "star";
|
||||
public static final String GROUP_MOONS = "moon";
|
||||
public static final String GROUP_GASCLOUDS = "gascloud";
|
||||
public static final String GROUP_ASTEROIDS = "asteroid";
|
||||
|
||||
private static RandomCollection<Star> stars = new RandomCollection<Star>();
|
||||
private static RandomCollection<Planetoid> moons = new RandomCollection<Planetoid>();
|
||||
private static RandomCollection<Planetoid> gasClouds = new RandomCollection<Planetoid>();
|
||||
private static RandomCollection<Asteroid> gasClouds = new RandomCollection<Asteroid>();
|
||||
private static RandomCollection<Asteroid> asteroids = new RandomCollection<Asteroid>();
|
||||
|
||||
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!");
|
||||
}
|
||||
|
@ -49,13 +44,7 @@ public class StructureManager {
|
|||
|
||||
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 exception) {
|
||||
WarpDrive.logger.error("Error loading file " + file.getName() + ": " + exception.getMessage());
|
||||
exception.printStackTrace();
|
||||
|
@ -64,186 +53,97 @@ public class StructureManager {
|
|||
}
|
||||
|
||||
private static void loadXmlStructureFile(File file) throws SAXException, IOException, InvalidXmlException {
|
||||
Document base = WarpDriveConfig.getXmlDocumentBuilder().parse(file);
|
||||
WarpDrive.logger.info("Loading structure data file " + file.getName());
|
||||
Document document = WarpDriveConfig.getXmlDocumentBuilder().parse(file);
|
||||
|
||||
ModCheckResults res = XmlPreprocessor.checkModRequirements(base.getDocumentElement());
|
||||
|
||||
if (!res.isEmpty()) {
|
||||
WarpDrive.logger.info("Skippping structure " + file.getName() + " due to " + res);
|
||||
// pre-process the file
|
||||
String result = XmlPreprocessor.checkModRequirements(document.getDocumentElement());
|
||||
if (!result.isEmpty()) {
|
||||
WarpDrive.logger.info("Skipping structure " + file.getName() + " due to " + result);
|
||||
return;
|
||||
}
|
||||
|
||||
XmlPreprocessor.doModReqSanitation(base);
|
||||
XmlPreprocessor.doLogicPreprocessing(base);
|
||||
XmlPreprocessor.doModReqSanitation(document);
|
||||
XmlPreprocessor.doLogicPreprocessing(document);
|
||||
|
||||
NodeList structures = base.getElementsByTagName("structure");
|
||||
for (int i = 0; i < structures.getLength(); i++) {
|
||||
// only add FillerSets
|
||||
NodeList nodeListStructures = document.getElementsByTagName("structure");
|
||||
for (int structureIndex = 0; structureIndex < nodeListStructures.getLength(); structureIndex++) {
|
||||
|
||||
Element struct = (Element) structures.item(i);
|
||||
Element elementStructure = (Element) nodeListStructures.item(structureIndex);
|
||||
|
||||
String group = struct.getAttribute("group");
|
||||
String name = struct.getAttribute("name");
|
||||
String group = elementStructure.getAttribute("group");
|
||||
if (group.isEmpty()) {
|
||||
throw new InvalidXmlException("Structure " + (structureIndex + 1) + "/" + nodeListStructures.getLength() + " is missing a group attribute!");
|
||||
}
|
||||
|
||||
WarpDrive.logger.info("Loading structure " + name);
|
||||
String name = elementStructure.getAttribute("name");
|
||||
if (name.isEmpty()) {
|
||||
throw new InvalidXmlException("Structure " + (structureIndex + 1) + "/" + nodeListStructures.getLength() + " is missing a name attribute!");
|
||||
}
|
||||
|
||||
if (group.isEmpty())
|
||||
throw new InvalidXmlException("Structure must have a group!");
|
||||
WarpDrive.logger.info("- found structure " + group + ":" + name);
|
||||
|
||||
int radius = 0;
|
||||
|
||||
if (group.equalsIgnoreCase("star")) {
|
||||
stars.loadFromXML(new Star(radius), struct);
|
||||
} else if (group.equalsIgnoreCase("moon")) {
|
||||
moons.loadFromXML(new Planetoid(radius), struct);
|
||||
} else if (group.equalsIgnoreCase("asteroid")) {
|
||||
asteroids.loadFromXML(new Asteroid(), struct);
|
||||
switch (group) {
|
||||
case GROUP_STARS:
|
||||
stars.loadFromXML(new Star(name), elementStructure);
|
||||
break;
|
||||
case GROUP_MOONS:
|
||||
moons.loadFromXML(new Planetoid(name), elementStructure);
|
||||
break;
|
||||
case GROUP_ASTEROIDS:
|
||||
asteroids.loadFromXML(new Asteroid(name), elementStructure);
|
||||
break;
|
||||
case GROUP_GASCLOUDS:
|
||||
gasClouds.loadFromXML(new Asteroid(name), elementStructure);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidXmlException("Structure " + (structureIndex + 1) + "/" + nodeListStructures.getLength() + " has invalid group " + group);
|
||||
// break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static DeployableStructure getStructure(Random random, final String name, final String type) {
|
||||
public static DeployableStructure getStructure(Random random, final String group, final String name) {
|
||||
if (name == null || name.length() == 0) {
|
||||
if (type == null || type.length() == 0) {
|
||||
return stars.next(random);
|
||||
} else if (type.equalsIgnoreCase("star")) {
|
||||
return stars.next(random);
|
||||
} else if (type.equalsIgnoreCase("moon")) {
|
||||
return moons.next(random);
|
||||
} else if (type.equalsIgnoreCase("asteroid")) {
|
||||
return asteroids.next(random);
|
||||
if (group == null || group.isEmpty()) {
|
||||
return null;
|
||||
} else if (group.equalsIgnoreCase(GROUP_STARS)) {
|
||||
return stars.getRandomEntry(random);
|
||||
} else if (group.equalsIgnoreCase(GROUP_MOONS)) {
|
||||
return moons.getRandomEntry(random);
|
||||
} else if (group.equalsIgnoreCase(GROUP_ASTEROIDS)) {
|
||||
return asteroids.getRandomEntry(random);
|
||||
}
|
||||
} else {
|
||||
for (Star star : stars.elements()) {
|
||||
if (star.getName().equals(name))
|
||||
return star;
|
||||
if (group == null || group.isEmpty()) {
|
||||
return null;
|
||||
} else if (group.equalsIgnoreCase(GROUP_STARS)) {
|
||||
return stars.getNamedEntry(name);
|
||||
} else if (group.equalsIgnoreCase(GROUP_MOONS)) {
|
||||
return moons.getNamedEntry(name);
|
||||
} else if (group.equalsIgnoreCase(GROUP_ASTEROIDS)) {
|
||||
return asteroids.getNamedEntry(name);
|
||||
}
|
||||
}
|
||||
|
||||
// not found or nothing defined => return null
|
||||
// not found or nothing defined
|
||||
return null;
|
||||
}
|
||||
|
||||
public static DeployableStructure getStar(Random random, final String name) {
|
||||
return getStructure(random, name, "star");
|
||||
return getStructure(random, GROUP_STARS, name);
|
||||
}
|
||||
|
||||
public static DeployableStructure getMoon(Random random, final String name) {
|
||||
return getStructure(random, name, "moon");
|
||||
return getStructure(random, GROUP_MOONS, name);
|
||||
}
|
||||
|
||||
public static DeployableStructure getAsteroid(Random random, final String name) {
|
||||
return getStructure(random, name, "asteroid");
|
||||
return getStructure(random, GROUP_ASTEROIDS, name);
|
||||
}
|
||||
|
||||
public static DeployableStructure getGasCloud(Random random, final String name) {
|
||||
return getStructure(random, name, "cloud");
|
||||
}
|
||||
|
||||
/**
|
||||
* Collection of elements with weights. Helps to select element with controlled odds.
|
||||
*
|
||||
* @author ncrashed
|
||||
*
|
||||
* @param <E>
|
||||
*/
|
||||
private static class RandomCollection<E extends XmlRepresentable> {
|
||||
private final NavigableMap<Double, E> weightMap = new TreeMap<Double, E>();
|
||||
private double totalWeight = 0;
|
||||
private final NavigableMap<Double, E> ratioMap = new TreeMap<Double, E>();
|
||||
private double totalRatio = 0;
|
||||
private final ArrayList<E> list = new ArrayList<E>();
|
||||
|
||||
|
||||
/**
|
||||
* Add new object and its weight.
|
||||
* @param weight Used for random pick. The higher the value is relatively to others, the higher odds of choosing the object.
|
||||
* @param obj Object to add
|
||||
*/
|
||||
public void add(double weight, E obj) {
|
||||
if (weight <= 0) {
|
||||
WarpDrive.logger.warn("Structure weight is negative or zero, skipping");
|
||||
return;
|
||||
}
|
||||
totalWeight += weight;
|
||||
weightMap.put(totalWeight, obj);
|
||||
list.add(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new object and its ratio.
|
||||
* Warning: if total ratio goes higher than 1.0, element won't be added to collection.
|
||||
* @param ratio Chance of random pick in range (0, 1.0]. In contrast to weights, ratio is fixed and chances don't change if you add more elements.
|
||||
* @param obj Object to add
|
||||
*/
|
||||
public void addRatio(double ratio, E obj) {
|
||||
if (ratio <= 0 || ratio >= 1.0) {
|
||||
WarpDrive.logger.warn("Structure ratio isn't in (0, 1.0] bounds, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
if (totalRatio + ratio > 1.0) {
|
||||
WarpDrive.logger.warn("Structures total ratio is greater than 1.0, skipping");
|
||||
return;
|
||||
}
|
||||
totalRatio += ratio;
|
||||
ratioMap.put(totalRatio, obj);
|
||||
list.add(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick random object according their weights
|
||||
* @param random
|
||||
* @return Random object or null if there is no objects to pick.
|
||||
*/
|
||||
public E next(Random random) {
|
||||
double value = random.nextDouble();
|
||||
|
||||
if (value < totalRatio) { // hit ratio part of values
|
||||
return ratioMap.ceilingEntry(value).getValue();
|
||||
} else { // hit dynamic part of values, weighted ones
|
||||
double weight = (value - totalRatio)*totalWeight;
|
||||
return weightMap.ceilingEntry(weight).getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return All registered objects
|
||||
*/
|
||||
public ArrayList<E> elements() {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads object from given XML element and parses configurations for weighted pick.
|
||||
* @param obj Object to load from *struct*
|
||||
* @param struct Part of XML config
|
||||
* @throws InvalidXmlException
|
||||
*/
|
||||
public void loadFromXML(E obj, Element struct) throws InvalidXmlException {
|
||||
obj.loadFromXmlElement(struct);
|
||||
|
||||
try {
|
||||
String ratioStr = struct.getAttribute("ratio");
|
||||
if(!ratioStr.isEmpty()) {
|
||||
double ratio = Double.parseDouble(ratioStr);
|
||||
this.addRatio(ratio, obj);
|
||||
} else { // try weight
|
||||
try {
|
||||
int weight = 1;
|
||||
String weightStr = struct.getAttribute("weight");
|
||||
if(!weightStr.isEmpty()) {
|
||||
weight = Integer.parseInt(weightStr);
|
||||
weight = Math.max(1, weight);
|
||||
}
|
||||
|
||||
this.add(weight, obj);
|
||||
} catch (NumberFormatException gdbg) {
|
||||
throw new InvalidXmlException("Weight must be int!");
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException gdbg) {
|
||||
throw new InvalidXmlException("Ratio must be double!");
|
||||
}
|
||||
}
|
||||
return getStructure(random, GROUP_GASCLOUDS, name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,13 +65,14 @@ public final class EntitySphereGen extends Entity {
|
|||
|
||||
private ArrayList<JumpBlock> blocks;
|
||||
private Orb orb;
|
||||
private int[] thicknesses;
|
||||
private boolean replace;
|
||||
|
||||
public EntitySphereGen(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
public EntitySphereGen(World world, int x, int y, int z, int radius, Orb orb, boolean replace) {
|
||||
public EntitySphereGen(World world, int x, int y, int z, Orb orb, int[] thicknesses, int radius, boolean replace) {
|
||||
super(world);
|
||||
this.xCoord = x;
|
||||
this.posX = x;
|
||||
|
@ -86,6 +87,7 @@ public final class EntitySphereGen extends Entity {
|
|||
blocks = new ArrayList<JumpBlock>(this.pregenSize);
|
||||
this.ticksDelay = world.rand.nextInt(60);
|
||||
this.orb = orb;
|
||||
this.thicknesses = thicknesses;
|
||||
this.replace = replace;
|
||||
}
|
||||
|
||||
|
@ -97,10 +99,10 @@ public final class EntitySphereGen extends Entity {
|
|||
|
||||
@Override
|
||||
public void onUpdate() {
|
||||
if (FMLCommonHandler.instance().getEffectiveSide().isClient()) {
|
||||
if (worldObj.isRemote) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (ticksDelay > 0) {
|
||||
ticksDelay--;
|
||||
return;
|
||||
|
@ -171,10 +173,10 @@ public final class EntitySphereGen extends Entity {
|
|||
if (dSq > radius)
|
||||
continue;
|
||||
|
||||
int rad = (int) Math.ceil(dSq);
|
||||
int range = (int) Math.ceil(dSq);
|
||||
|
||||
// Add blocks to memory
|
||||
OrbShell orbShell = orb.getShellForRadius(rad);
|
||||
OrbShell orbShell = orb.getShellForRadius(thicknesses, range);
|
||||
MetaBlock metablock = orbShell.getRandomBlock(rand);
|
||||
addBlock(new JumpBlock(metablock.block, metablock.metadata, xCoord + x, yCoord + y, zCoord + z));
|
||||
|
||||
|
@ -208,8 +210,9 @@ public final class EntitySphereGen extends Entity {
|
|||
}
|
||||
|
||||
private void addBlock(JumpBlock jb) {
|
||||
if (blocks == null)
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
// Replace water with random gas (ship in moon)
|
||||
if (worldObj.getBlock(jb.x, jb.y, jb.z).isAssociatedBlock(Blocks.water)) {
|
||||
if (worldObj.rand.nextInt(50) != 1) {
|
||||
|
@ -220,8 +223,9 @@ public final class EntitySphereGen extends Entity {
|
|||
return;
|
||||
}
|
||||
// Do not replace existing blocks if fillingSphere is true
|
||||
if (!replace && !worldObj.isAirBlock(jb.x, jb.y, jb.z))
|
||||
if (!replace && !worldObj.isAirBlock(jb.x, jb.y, jb.z)) {
|
||||
return;
|
||||
}
|
||||
blocks.add(jb);
|
||||
}
|
||||
|
||||
|
|
|
@ -269,7 +269,6 @@ public class SpaceWorldGenerator implements IWorldGenerator {
|
|||
public static void generateRandomAsteroid(World world, int x, int y, int z) {
|
||||
|
||||
DeployableStructure asteroid = StructureManager.getAsteroid(world.rand, null);
|
||||
WarpDrive.logger.info("Generating asteroid (class " + asteroid + ") at " + x + " " + y + " " + z);
|
||||
|
||||
asteroid.generate(world, world.rand, x, y, z);
|
||||
|
||||
|
@ -296,34 +295,37 @@ public class SpaceWorldGenerator implements IWorldGenerator {
|
|||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public static void generateSphereDirect(
|
||||
World world, int xCoord, int yCoord, int zCoord, Orb orb, Random rand) {
|
||||
double radiusC = orb.getHeight() / 2 + 0.5D; // Radius from center of block
|
||||
final int[] thicknesses, Orb orb, World world, int xCoord, int yCoord, int zCoord) {
|
||||
int totalThickness = 0;
|
||||
for (int thickness : thicknesses) {
|
||||
totalThickness += thickness;
|
||||
}
|
||||
double radiusC = totalThickness + 0.5D; // Radius from center of block
|
||||
double radiusSq = radiusC * radiusC; // Optimization to avoid sqrts...
|
||||
// sphere
|
||||
int ceilRadius = (int) Math.ceil(radiusC);
|
||||
|
||||
|
||||
// Pass the cube and check points for sphere equation x^2 + y^2 + z^2 = r^2
|
||||
for (int x = 0; x <= ceilRadius; x++) {
|
||||
double x2 = (x + 0.5D) * (x + 0.5D);
|
||||
double dX2 = (x + 0.5D) * (x + 0.5D);
|
||||
for (int y = 0; y <= ceilRadius; y++) {
|
||||
double y2 = (y + 0.5D) * (y + 0.5D);
|
||||
double dX2Y2 = dX2 + (y + 0.5D) * (y + 0.5D);
|
||||
for (int z = 0; z <= ceilRadius; z++) {
|
||||
double z2 = (z + 0.5D) * (z + 0.5D);
|
||||
int dSq = (int) Math.sqrt(x2 + y2 + z2); // Distance from current position
|
||||
//TODO: Find quicker form of sqrt
|
||||
|
||||
double dZ2 = (z + 0.5D) * (z + 0.5D);
|
||||
double dSq = dX2Y2 + dZ2; // squared distance from current position
|
||||
|
||||
// Skip too far blocks
|
||||
if (dSq > radiusSq) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Place blocks
|
||||
// cheat by using axial symmetry so we don't create random numbers too frequently
|
||||
|
||||
OrbShell orbShell = orb.getShellForRadius(dSq);
|
||||
MetaBlock metablock = orbShell.getRandomBlock(rand);
|
||||
|
||||
OrbShell orbShell = orb.getShellForRadius(thicknesses, (int)Math.sqrt(dSq));
|
||||
MetaBlock metablock = orbShell.getRandomBlock(world.rand);
|
||||
world.setBlock(xCoord + x, yCoord + y, zCoord + z, metablock.block, metablock.metadata, 2);
|
||||
world.setBlock(xCoord - x, yCoord + y, zCoord + z, metablock.block, metablock.metadata, 2);
|
||||
world.setBlock(xCoord + x, yCoord - y, zCoord + z, metablock.block, metablock.metadata, 2);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<warpdriveWorldGeneration version="1">
|
||||
|
||||
<FillerSet group="stone_ores">
|
||||
<FillerSet group="stone_ores" name="default_stone_ores">
|
||||
<filler block="minecraft:coal_ore" ratio=".08" />
|
||||
<filler block="minecraft:iron_ore" ratio=".05" />
|
||||
<filler block="minecraft:redstone_ore" ratio=".05" />
|
||||
|
@ -32,20 +32,20 @@
|
|||
<filler block="minecraft:bedrock" ratio=".001" />
|
||||
</FillerSet>
|
||||
|
||||
<FillerSet group="commonOres">
|
||||
<FillerSet group="commonOres" name="default_commonOres">
|
||||
<filler block="minecraft:coal_ore" ratio=".08" />
|
||||
<filler block="minecraft:iron_ore" ratio=".05" />
|
||||
<filler block="IC2:blockOreTin" ratio=".05" />
|
||||
<filler block="IC2:blockOreCopper" ratio=".06" />
|
||||
</FillerSet>
|
||||
|
||||
<FillerSet group="uncommonOres">
|
||||
<FillerSet group="uncommonOres" name="default_uncommonOres">
|
||||
<filler block="minecraft:redstone_ore" ratio=".02" />
|
||||
<filler block="IC2:blockOreUran" ratio=".001" mods="IC2" />
|
||||
<filler block="ae2:quartz" ratio=".01" mods="appliedenergistics2" />
|
||||
</FillerSet>
|
||||
|
||||
<FillerSet group="rareOres">
|
||||
<FillerSet group="rareOres" name="default_rareOres">
|
||||
<filler block="minecraft:gold_ore" ratio=".008" />
|
||||
<filler block="minecraft:diamond_ore" ratio=".001" />
|
||||
<filler block="minecraft:lapis_ore" ratio=".005" />
|
||||
|
@ -53,19 +53,19 @@
|
|||
<filler block="warpdrive:iridiumBlock" ratio=".0001" />
|
||||
</FillerSet>
|
||||
|
||||
<FillerSet group="overworld">
|
||||
<FillerSet group="overworld" name="default_overworld">
|
||||
<filler block="minecraft:stone" weight="200" />
|
||||
<filler block="minecraft:sand" weight="30" />
|
||||
<filler block="minecraft:dirt" weight="50" />
|
||||
</FillerSet>
|
||||
|
||||
<FillerSet group="end">
|
||||
<FillerSet group="end" name="default_end">
|
||||
<filler block="minecraft:end_stone" weight="200" />
|
||||
<filler block="minecraft:sand" weight="20" />
|
||||
<filler block="minecraft:obsidian" weight="20" />
|
||||
</FillerSet>
|
||||
|
||||
<FillerSet group="nether">
|
||||
<FillerSet group="nether" name="default_nether">
|
||||
<filler block="minecraft:netherrack" weight="300" />
|
||||
<filler block="minecraft:quartz_ore" weight="20" />
|
||||
<filler block="minecraft:glowstone" weight="40" />
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<warpdriveWorldGeneration version="1" mods="netherores">
|
||||
|
||||
<FillerSet group="nether" >
|
||||
<FillerSet group="nether" name="netherores_nether">
|
||||
<filler block="netherores:ore" metadata="0" weight="50" />
|
||||
<filler block="netherores:ore" metadata="0" weight="40" />
|
||||
<filler block="netherores:ore" metadata="0" weight="30" />
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<for variable="type" in="igneous,metamorphic,sedimentary">
|
||||
<for variable="metadata" from="0" to="7">
|
||||
<FillerSet group="%type%_ores@%metadata%">
|
||||
<FillerSet group="stone_ores" name="%type%_ores@%metadata%">
|
||||
<filler block="UndergroundBiomes:%type%_oreCoal" metadata="%metadata%" ratio=".001" />
|
||||
<filler block="UndergroundBiomes:%type%_oreDiamond" metadata="%metadata%" ratio=".001" />
|
||||
<filler block="UndergroundBiomes:%type%_oreEmerald" metadata="%metadata%" ratio=".001" />
|
||||
|
@ -15,11 +15,11 @@
|
|||
<filler block="UndergroundBiomes:%type%_oreRedstone" metadata="%metadata%" ratio=".001" />
|
||||
</FillerSet>
|
||||
|
||||
<FillerSet group="%type%_ores@%metadata%.normal" fillerSets="%type%_ores@%metadata%">
|
||||
<FillerSet group="overworld" name="%type%_ores@%metadata%.normal" fillerSets="%type%_ores@%metadata%">
|
||||
<filler block="UndergroundBiomes:%type%Stone" metadata="%metadata%" weight="10" />
|
||||
</FillerSet>
|
||||
|
||||
<FillerSet group="%type%_ores@%metadata%.corrupted" fillerSets="%type%_ores@%metadata%">
|
||||
<FillerSet group="overworld" name="%type%_ores@%metadata%.corrupted" fillerSets="%type%_ores@%metadata%">
|
||||
<filler block="UndergroundBiomes:%type%Cobblestone" metadata="%metadata%" weight="10" />
|
||||
</FillerSet>
|
||||
|
||||
|
|
|
@ -3,22 +3,87 @@
|
|||
|
||||
<warpdriveWorldGeneration version="1">
|
||||
|
||||
<structure group="star" name="red_giant">
|
||||
<shell name="core" maxThickness="10" minThickness="3">
|
||||
<filler weight="1" block="minecraft:iron_ore" />
|
||||
<structure group="star" name="red_dwarf">
|
||||
<shell name="core" minThickness="40" maxThickness="50"><!-- legacy radius was 42 -->
|
||||
<filler weight="1" block="minecraft:redstone_block" />
|
||||
</shell>
|
||||
|
||||
<shell name="mantle" minThickness="10" maxThickness="25">
|
||||
<filler weight="10" block="minecraft:sand" />
|
||||
<filler weight="1" block="minecraft:iron_block" />
|
||||
<shell name="low_altitude" minThickness="4" maxThickness="6">
|
||||
<filler weight="1" block="WarpDrive:blockGas" metadata="1" />
|
||||
</shell>
|
||||
|
||||
<shell name="surface" minThickness="10" maxThickness="20">
|
||||
<filler weight="5" block="minecraft:glowstone" />
|
||||
<filler weight="10" block="minecraft:lava" />
|
||||
<shell name="atmosphere" minThickness="2" maxThickness="2">
|
||||
<filler weight="1" block="WarpDrive:blockGas" metadata="1" />
|
||||
</shell>
|
||||
</structure>
|
||||
|
||||
<structure group="star" name="orange_dwarf">
|
||||
<shell name="core" minThickness="1" maxThickness="1"><!-- mark the center -->
|
||||
<filler weight="1" block="minecraft:obsidian" />
|
||||
</shell>
|
||||
<shell name="mantle_air" minThickness="35" maxThickness="45"><!-- add bedrock to prevent warping inside -->
|
||||
<filler ratio="0.005" block="minecraft:bedrock" />
|
||||
<filler ratio="0.005" block="minecraft:glowstone" />
|
||||
<filler weight="1" block="minecraft:air" />
|
||||
</shell>
|
||||
<shell name="mantle_inner" minThickness="1" maxThickness="1"><!-- add light source and solid block to protect inner side -->
|
||||
<filler weight="1" block="minecraft:glowstone" />
|
||||
</shell>
|
||||
<shell name="mantle_outer" minThickness="2" maxThickness="2">
|
||||
<filler weight="1" block="minecraft:lava" />
|
||||
</shell>
|
||||
<shell name="surface" minThickness="1" maxThickness="1"><!-- add stained glass for color and holding fluid in place -->
|
||||
<filler weight="1" block="minecraft:stained_glass" metadata="14" />
|
||||
</shell>
|
||||
</structure>
|
||||
|
||||
<structure group="star" name="yellow_giant">
|
||||
<shell name="core" minThickness="1" maxThickness="1"><!-- mark the center -->
|
||||
<filler weight="1" block="minecraft:obsidian" />
|
||||
</shell>
|
||||
<shell name="mantle_air" minThickness="55" maxThickness="70"><!-- add bedrock to prevent warping inside -->
|
||||
<filler ratio="0.005" block="minecraft:bedrock" />
|
||||
<filler ratio="0.005" block="minecraft:glowstone" />
|
||||
<filler weight="1" block="minecraft:air" />
|
||||
</shell>
|
||||
<shell name="mantle_inner" minThickness="2" maxThickness="2"><!-- add light source and solid block to protect inner side -->
|
||||
<filler weight="1" block="minecraft:glowstone" />
|
||||
</shell>
|
||||
<shell name="surface" minThickness="1" maxThickness="1"><!-- add stained glass for color -->
|
||||
<filler weight="1" block="minecraft:stained_glass" metadata="1" />
|
||||
</shell>
|
||||
<shell name="low_altitude" minThickness="4" maxThickness="6">
|
||||
<filler weight="1" block="minecraft:air" />
|
||||
</shell>
|
||||
<shell name="atmosphere" minThickness="1" maxThickness="1"><!-- add stained glass for color -->
|
||||
<filler weight="1" block="minecraft:stained_glass" metadata="4" />
|
||||
</shell>
|
||||
</structure>
|
||||
|
||||
<structure group="star" name="yellow_supergiant">
|
||||
<shell name="core" minThickness="1" maxThickness="1"><!-- mark the center -->
|
||||
<filler weight="1" block="minecraft:obsidian" />
|
||||
</shell>
|
||||
<shell name="mantle_air" minThickness="70" maxThickness="90"><!-- add bedrock to prevent warping inside -->
|
||||
<filler ratio="0.01" block="minecraft:bedrock" />
|
||||
<filler weight="1" block="minecraft:air" />
|
||||
</shell>
|
||||
<shell name="mantle_inner" minThickness="2" maxThickness="2"><!-- add light source and solid block to protect inner side -->
|
||||
<filler weight="1" block="minecraft:glowstone" />
|
||||
</shell>
|
||||
<shell name="surface" minThickness="1" maxThickness="1"><!-- add stained glass for color -->
|
||||
<filler weight="1" block="minecraft:stained_glass" metadata="1" />
|
||||
</shell>
|
||||
<shell name="low_altitude" minThickness="4" maxThickness="6">
|
||||
<filler weight="1" block="minecraft:air" />
|
||||
</shell>
|
||||
<shell name="atmosphere" minThickness="1" maxThickness="1"><!-- add stained glass for color -->
|
||||
<filler weight="1" block="WarpDrive:blockGas" metadata="3" />
|
||||
</shell>
|
||||
</structure>
|
||||
|
||||
|
||||
|
||||
<structure group="moon" name="theMoon">
|
||||
<shell name="core" minThickness="1" maxThickness="5" fillerSets="rareOres">
|
||||
<filler weight="100" block="minecraft:iron_ore" />
|
||||
|
@ -68,22 +133,24 @@
|
|||
</shell>
|
||||
</structure>
|
||||
|
||||
<structure group="asteroid" name="ClusteredAsteroid" weight="3" coreBlock="minecraft:iron_ore" maxCoreSize="10" minCoreSize="6" coreRad="0.5">
|
||||
<shell name="mantle" minThickness="5" maxThickness="15" fillerSets="commonOres,uncommonOres">
|
||||
|
||||
|
||||
<structure group="asteroid" name="ClusteredAsteroid" weight="3" coreBlock="minecraft:iron_ore" minCoreCount="6" maxCoreCount="10" relativeCoreRadius="0.5">
|
||||
<shell name="mantle" minThickness="1" maxThickness="6" fillerSets="commonOres,uncommonOres">
|
||||
<filler weight="10" block="minecraft:stone" />
|
||||
<filler weight="5" block="minecraft:cobblestone" />
|
||||
</shell>
|
||||
</structure>
|
||||
|
||||
<structure group="asteroid" name="SphericalAsteroid" weight="10" coreBlock="minecraft:iron_ore" maxCoreSize="3" minCoreSize="1" coreRad="0.1">
|
||||
<shell name="mantle" minThickness="5" maxThickness="10" fillerSets="commonOres,uncommonOres">
|
||||
<structure group="asteroid" name="SphericalAsteroid" weight="10" coreBlock="minecraft:iron_ore" minCoreCount="1" maxCoreCount="3" relativeCoreRadius="0.1">
|
||||
<shell name="mantle" minThickness="1" maxThickness="6" fillerSets="commonOres,uncommonOres">
|
||||
<filler weight="10" block="minecraft:stone" />
|
||||
<filler weight="5" block="minecraft:cobblestone" />
|
||||
</shell>
|
||||
</structure>
|
||||
|
||||
<structure group="asteroid" name="diamondGeode" weight="2" coreBlock="minecraft:diamond_ore" maxCoreSize="2" minCoreSize="1" coreRad="0.1">
|
||||
<shell name="mantle" minThickness="5" maxThickness="10" fillerSets="commonOres">
|
||||
<structure group="asteroid" name="diamondGeode" weight="2" coreBlock="minecraft:diamond_ore" minCoreCount="1" maxCoreCount="2" relativeCoreRadius="0.1">
|
||||
<shell name="mantle" minThickness="1" maxThickness="6" fillerSets="commonOres">
|
||||
<filler weight="10" block="minecraft:stone" />
|
||||
<filler weight="5" block="minecraft:cobblestone" />
|
||||
</shell>
|
||||
|
|
Loading…
Reference in a new issue