Refactored world generation

Bumped XML to version 2
Refactored Java structure to match XML content (deployable vs structure, MetaBlock vs filler, Asteroid to MetaOrb, SchematicStructure to Schematic, etc.)
Refactored Java class names to have 'abstract' in their name when they are abstract
Refactored XML importations to use explicit import element
Refactored XML FillerSet to fillerSet
Replaced FillerManager with RandomCollection
Refactored structures to have groups too
Added list of structures to the /generate command
Added XML schema validation
Added more variations with explicit instanciation and dynamic imports
Added more specific console logs during world generation
Reimplemented gas clouds
Reimplemented hidden derelict ship
Disabled netherores configuration for now
Fixed world corruption on asteroids core block (invalid metadata)
Fixed maxCoreCount & maxThickness never occurring
Fixed static importations so they actually import stuff
Fixed import action corrupting weights & ratios
Fixed overlapping default fillerSets
Fixed undergroundBiomes having no igneous cobblestone
Fixed random collection failing when no weight is defined
Improved logging of overlapping and out of range entries
Improved logging spam during boot and generation through logging options
This commit is contained in:
LemADEC 2016-01-20 23:42:50 +01:00
parent 8d143c50d9
commit baede10546
31 changed files with 2056 additions and 1323 deletions

View file

@ -7,7 +7,7 @@ import net.minecraft.util.MathHelper;
import cpw.mods.fml.common.FMLCommonHandler;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.config.structures.DeployableStructure;
import cr0s.warpdrive.config.structures.AbstractStructure;
import cr0s.warpdrive.config.structures.StructureManager;
import cr0s.warpdrive.world.JumpgateGenerator;
import cr0s.warpdrive.world.WorldGenSmallShip;
@ -52,11 +52,7 @@ public class CommandGenerate extends CommandBase {
int z = MathHelper.floor_double(player.posZ);
if (FMLCommonHandler.instance().getEffectiveSide().isServer()) {
if (struct.equals("moon")) {
WarpDrive.logger.info("/generate: generating moon at " + x + ", " + (y - 16) + ", " + z);
WarpDrive.instance.spaceWorldGenerator.generateMoon(player.worldObj, x, y - 16, z, null);
} else if (struct.equals("ship")) {
if (struct.equals("ship")) {
WarpDrive.logger.info("/generate: generating NPC ship at " + x + ", " + y + ", " + z);
new WorldGenSmallShip(false).generate(player.worldObj, player.worldObj.rand, x, y, z);
@ -65,30 +61,29 @@ public class CommandGenerate extends CommandBase {
new WorldGenStation(false).generate(player.worldObj, player.worldObj.rand, x, y, z);
} else if (struct.equals("asteroid")) {
WarpDrive.logger.info("/generate: generating asteroid at " + x + ", " + (y - 10) + ", " + z);
WarpDrive.instance.spaceWorldGenerator.generateRandomAsteroid(player.worldObj, x, y - 10, z);
String name = (params.length > 1) ? params[1] : null;
generateStructure(player, StructureManager.GROUP_ASTEROIDS, name, x, y - 10, z);
} else if (struct.equals("astfield")) {
WarpDrive.logger.info("/generate: generating asteroid field at " + x + ", " + y + ", " + z);
WarpDrive.instance.spaceWorldGenerator.generateAsteroidField(player.worldObj, x, y, z);
} else if (struct.equals("gascloud")) {
WarpDrive.logger.info("/generate: generating gas cloud at " + x + ", " + y + ", " + z);
String type = (params.length > 1) ? params[1] : null;
WarpDrive.instance.spaceWorldGenerator.generateGasCloudOfColor(player.worldObj, x, y, z, 15, 20, type);
String name = (params.length > 1) ? params[1] : null;
generateStructure(player, StructureManager.GROUP_GASCLOUDS, name, x, y, z);
} else if (struct.equals("moon")) {
String name = (params.length > 1) ? params[1] : null;
generateStructure(player, StructureManager.GROUP_MOONS, name, x, y - 16, z);
} else if (struct.equals("star")) {
String type = (params.length > 1) ? params[1] : null;
DeployableStructure star = StructureManager.getStar(player.worldObj.rand, type);
if (star == null) {
WarpDrive.addChatMessage(player, "Invalid star type '" + type + "'");
} else {
WarpDrive.logger.info("/generate: Generating star (class " + star + ") at " + x + " " + y + " " + z);
star.generate(player.worldObj, player.worldObj.rand, x, y, z);
}
String name = (params.length > 1) ? params[1] : null;
generateStructure(player, StructureManager.GROUP_STARS, name, x, y, z);
} else if (struct.equals("jumpgate")) {
if (params.length == 2) {
if (params.length != 2) {
WarpDrive.addChatMessage(player, "Missing jumpgate name");
} else {
WarpDrive.logger.info("/generate: creating jumpgate at " + x + ", " + y + ", " + z);
if (WarpDrive.jumpgates.addGate(params[1], x, y, z)) {
@ -105,4 +100,21 @@ public class CommandGenerate extends CommandBase {
WarpDrive.addChatMessage(player, getCommandUsage(icommandsender));
}
}
private void generateStructure(EntityPlayerMP player, final String group, final String name, final int x, final int y, final int z) {
AbstractStructure structure = StructureManager.getStructure(player.worldObj.rand, group, name);
if (structure == null) {
WarpDrive.addChatMessage(player, "Invalid " + group + " '" + name + "', try one of the followings:\n" + StructureManager.getStructureNames(group));
} else {
WarpDrive.logger.info("/generate: Generating " + group + ":" + structure.getName() + " at " + x + " " + y + " " + z);
structure.generate(player.worldObj, player.worldObj.rand, x, y, z);
// do a weak attempt to extract player (ideally, it should be delayed after generation, but that's too complicated)
int newY = y + 1;
while (newY < 256 && !player.worldObj.isAirBlock(x, newY, z)) {
newY++;
}
player.setPosition(player.posX, newY, player.posZ);
}
}
}

View file

@ -1,76 +0,0 @@
package cr0s.warpdrive.config;
import java.util.HashMap;
import net.minecraft.block.Block;
/**
* Immutable class used to represent a block with metadata. An instance can only be retrieved with getMetaBlock(), which allows it to reuse instances
*
* @author TheNumenorean
*
*/
public class MetaBlock implements Comparable {
public static final int MAX_METADATA = 16;
private static HashMap<String, MetaBlock[]> metablocks = new HashMap<String, MetaBlock[]>();
// values can only be read, no need for getter/setter
public final Block block;
public final int metadata;
private MetaBlock(Block block, int metadata) {
this.block = block;
this.metadata = metadata;
}
/**
* Gets an instance of a metablock with the given block and metadata information.
*
* @param block
* Block to use (non null)
* @param metadata
* Metadata to use (0-15)
* @return A MetaBlock
*/
public static MetaBlock getMetaBlock(Block block, int metadata) {
if (block == null) {
throw new IllegalArgumentException("Block can't be null");
}
if (metadata < 0 || metadata >= MAX_METADATA) {
throw new IllegalArgumentException("Metadata out of range in " + block.getUnlocalizedName() + ":" + metadata + ". Expecting 0 to " + (MAX_METADATA - 1));
}
MetaBlock[] metablock = metablocks.get(block.getUnlocalizedName());
if (metablock == null) {
metablock = new MetaBlock[MAX_METADATA];
metablocks.put(block.getUnlocalizedName(), metablock);
}
if (metablock[metadata] == null) {
metablock[metadata] = new MetaBlock(block, metadata);
}
return metablock[metadata];
}
@Override
public int compareTo(Object object) {
int strComp = block.getUnlocalizedName().compareTo(((MetaBlock) object).block.getUnlocalizedName());
return strComp != 0 ? strComp : metadata - ((MetaBlock) object).metadata;
}
@Override
public String toString() {
return block.getUnlocalizedName() + ":" + metadata;
}
@Override
public int hashCode() {
return Block.getIdFromBlock(block) << 4 + metadata;
}
}

View file

@ -1,6 +1,7 @@
package cr0s.warpdrive.config;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.Random;
import java.util.TreeMap;
@ -10,15 +11,15 @@ import org.w3c.dom.Element;
import cr0s.warpdrive.WarpDrive;
/**
* Collection of elements with weights. Helps to select element with controlled odds.
* Collection of elements with ratios and weights. Helps to select element with controlled odds.
*
* @author ncrashed
* @author ncrashed, LemADEC
*
* @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<Integer, E> weightMap = new TreeMap<Integer, E>();
private int totalWeight = 0;
private final NavigableMap<Double, E> ratioMap = new TreeMap<Double, E>();
private double totalRatio = 0;
private final ArrayList<E> list = new ArrayList<E>();
@ -30,10 +31,14 @@ public class RandomCollection<E extends XmlRepresentable> {
* 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) {
**/
public void addWeight(final int weight, E object) {
if (weight <= 0) {
WarpDrive.logger.warn("Weight is negative or zero, skipping " + object);
WarpDrive.logger.warn("Weight is negative or zero, skipping " + object + " with weight " + weight);
return;
}
if (weightMap.containsValue(object)) {
WarpDrive.logger.warn("Object already has a weight defined, skipping " + object + " with weight " + weight);
return;
}
totalWeight += weight;
@ -48,15 +53,19 @@ public class RandomCollection<E extends XmlRepresentable> {
* 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) {
**/
public void addRatio(final double ratio, E object) {
if (ratio <= 0 || ratio >= 1.0) {
WarpDrive.logger.warn("Ratio isn't in (0, 1.0] bounds, skipping " + object);
WarpDrive.logger.warn("Ratio isn't in ]0, 1.0] bounds, skipping " + object + " with ratio " + ratio);
return;
}
if (ratioMap.containsValue(object)) {
WarpDrive.logger.warn("Object already has a ratio defined, skipping " + object + " with ratio " + ratio);
return;
}
if (totalRatio + ratio > 1.0) {
WarpDrive.logger.warn("Total ratio is greater than 1.0, skipping " + object);
WarpDrive.logger.warn("Total ratio is greater than 1.0, skipping " + object + " with ratio " + ratio);
return;
}
totalRatio += ratio;
@ -69,15 +78,31 @@ public class RandomCollection<E extends XmlRepresentable> {
*
* @param random
* @return Random object or null if there is no objects to pick.
*/
**/
public E getRandomEntry(Random random) {
double value = random.nextDouble();
if (totalWeight == 0.0D) {
value *= totalRatio;
}
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();
int weight = (int)Math.round((value - totalRatio) * totalWeight);
Entry<Integer, E> entry = weightMap.ceilingEntry(weight);
/*
WarpDrive.logger.info("value " + String.format("%.3f", value)
+ " => " + entry + " totals "
+ totalRatio + " " + totalWeight
+ " " + Arrays.toString(weightMap.navigableKeySet().toArray())
+ " " + Arrays.toString(weightMap.values().toArray()));
/**/
if (entry != null) {
return entry.getValue();
} else {
return null;
}
}
}
@ -86,7 +111,7 @@ public class RandomCollection<E extends XmlRepresentable> {
*
* @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)) {
@ -96,9 +121,28 @@ public class RandomCollection<E extends XmlRepresentable> {
return null;
}
/**
* Get a string listing all object names
*
* @return Formated string list separated by commas
**/
public String getNames() {
String names = "";
if (list.isEmpty()) {
return "-none defined-";
}
for(E object : list) {
if (!names.isEmpty()) {
names += ", ";
}
names += object.getName();
}
return names;
}
/**
* @return All registered objects
*/
**/
public ArrayList<E> elements() {
return list;
}
@ -111,31 +155,82 @@ public class RandomCollection<E extends XmlRepresentable> {
* @param element
* Element of an XML file
* @throws InvalidXmlException
*/
**/
public void loadFromXML(E object, Element element) throws InvalidXmlException {
object.loadFromXmlElement(element);
if (!object.loadFromXmlElement(element)) {// skip invalid entries
return;
}
try {
String ratioStr = element.getAttribute("ratio");
if (!ratioStr.isEmpty()) {
double ratio = Double.parseDouble(ratioStr);
addRatio(ratio, object);
} else { // try weight
// detect and handle loading of an existing object
E existing = getNamedEntry(object.getName());
if (existing != null) {
if (existing.equals(object)) {
// all good, nothing to do
if (WarpDriveConfig.LOGGING_WORLDGEN) {
WarpDrive.logger.info("Object already exists in collection, skipping " + object.getName());
}
return;
} else {
throw new InvalidXmlException("Invalid merge of different objects with the same name " + object.getName()
+ "\nnew entry is " + object
+ "\nwhile existing entry is " + existing + "");
}
}
// ratio takes priority over weight
String stringRatio = element.getAttribute("ratio");
if (!stringRatio.isEmpty()) {
double ratio = 0.1;
try {
ratio = Double.parseDouble(stringRatio);
} catch (NumberFormatException exceptionRatio) {
throw new InvalidXmlException("Ratio must be double!");
}
addRatio(ratio, object);
} else { // defaults to weight=1
int weight = 1;
String stringWeight = element.getAttribute("weight");
if (!stringWeight.isEmpty()) {
try {
int weight = 1;
String stringWeight = element.getAttribute("weight");
if (!stringWeight.isEmpty()) {
weight = Integer.parseInt(stringWeight);
weight = Math.max(1, weight);
}
addWeight(weight, object);
weight = Integer.parseInt(stringWeight);
} catch (NumberFormatException exceptionWeight) {
throw new InvalidXmlException("Weight must be an integer!");
}
weight = Math.max(1, weight);
}
} catch (NumberFormatException exceptionRatio) {
throw new InvalidXmlException("Ratio must be double!");
addWeight(weight, object);
}
}
/**
* Merge another random collection into this one.
*
* @param object
* Object to load into
* @param element
* Element of an XML file
* @throws InvalidXmlException
**/
public void loadFrom(RandomCollection<E> objects) throws InvalidXmlException {
int previousWeight = 0;
for (Entry<Integer, E> entry : objects.weightMap.entrySet()) {
addWeight(entry.getKey() - previousWeight, entry.getValue());
previousWeight = entry.getKey();
}
double previousRatio = 0.0D;
for (Entry<Double, E> entry : objects.ratioMap.entrySet()) {
addRatio(entry.getKey() - previousRatio, entry.getValue());
previousRatio = entry.getKey();
}
}
/**
* Return true when no content has been provided yet
*
* @return isEmpty
**/
public boolean isEmpty() {
return list.isEmpty();
}
}

View file

@ -11,6 +11,9 @@ import java.util.Arrays;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Loader;
@ -36,7 +39,6 @@ public class WarpDriveConfig {
"filler-default.xml", "filler-netherores.xml", "filler-undergroundbiomes.xml",
// structures
"structures-default.xml", "structures-netherores.xml",
// done
};
/*
@ -278,7 +280,6 @@ public class WarpDriveConfig {
public static Block getModBlock(final String mod, final String id) {
try {
return GameRegistry.findBlock(mod, id);
@ -728,7 +729,7 @@ public class WarpDriveConfig {
}
public static void onFMLPostInitialization() {
// read XML files
// unpack default XML files if none are defined
File[] files = configDirectory.listFiles(new FilenameFilter() {
@Override
public boolean accept(File file_notUsed, String name) {
@ -741,12 +742,14 @@ public class WarpDriveConfig {
}
}
FillerManager.loadOres(configDirectory);
StructureManager.loadStructures(configDirectory);
// always unpack the XML Schema
unpackResourceToFolder("WarpDrive.xsd", "config", configDirectory);
// load XML files
FillerManager.load(configDirectory);
StructureManager.load(configDirectory);
Dictionary.apply();
FillerManager.finishLoading();
}
private static void loadForgeMultipart() {
@ -791,22 +794,47 @@ public class WarpDriveConfig {
public static DocumentBuilder getXmlDocumentBuilder() {
if (xmlDocumentBuilder == null) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setIgnoringComments(false);
dbf.setValidating(true);
ErrorHandler xmlErrorHandler = new ErrorHandler() {
@Override
public void warning(SAXParseException exception) throws SAXException {
WarpDrive.logger.warn("XML warning: " + exception.getLocalizedMessage());
// exception.printStackTrace();
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
WarpDrive.logger.warn("XML fatal error: " + exception.getLocalizedMessage());
// exception.printStackTrace();
}
@Override
public void error(SAXParseException exception) throws SAXException {
WarpDrive.logger.warn("XML error: " + exception.getLocalizedMessage());
// exception.printStackTrace();
}
};
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setIgnoringComments(false);
documentBuilderFactory.setNamespaceAware(true);
documentBuilderFactory.setValidating(true);
documentBuilderFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
try {
xmlDocumentBuilder = dbf.newDocumentBuilder();
xmlDocumentBuilder = documentBuilderFactory.newDocumentBuilder();
} catch (ParserConfigurationException exception) {
exception.printStackTrace();
}
xmlDocumentBuilder.setErrorHandler(xmlErrorHandler);
}
return xmlDocumentBuilder;
}
/*
/**
* Copy a default configuration file from the mod's resources to the specified configuration folder
*/
**/
public static void unpackResourceToFolder(final String filename, final String sourceResourcePath, File targetFolder) {
// targetFolder is already created by caller

View file

@ -119,6 +119,9 @@ public class XmlPreprocessor {
// copy children with replaced variable
for(String variableValue : inOptions) {
if (WarpDriveConfig.LOGGING_WORLDGEN) {
WarpDrive.logger.info("Resolving for-loop with variable " + variableName + " = " + variableValue);
}
NodeList allChildren = root.getChildNodes();
for(int childIndex = 0; childIndex < allChildren.getLength(); childIndex ++) {
Node copy = copyNodeAndReplaceVariable(allChildren.item(childIndex), variableName, variableValue);
@ -143,8 +146,12 @@ public class XmlPreprocessor {
throw new InvalidXmlException(exception);
}
// copy children with replaced variable
for (int variableValue = intFrom; variableValue <= intTo; variableValue++) {
if (WarpDriveConfig.LOGGING_WORLDGEN) {
WarpDrive.logger.info("Resolving for-loop with variable " + variableName + " = " + variableValue);
}
NodeList allChildren = root.getChildNodes();
for (int childIndex = 0; childIndex < allChildren.getLength(); childIndex++) {
Node copy = copyNodeAndReplaceVariable(allChildren.item(childIndex), variableName, "" + variableValue);

View file

@ -6,7 +6,8 @@ import org.w3c.dom.Element;
public interface XmlRepresentable {
public String getName();
public void loadFromXmlElement(Element element) throws InvalidXmlException;
// Load the XML element, return true if successful
public boolean loadFromXmlElement(Element element) throws InvalidXmlException;
public void saveToXmlElement(Element element, Document document) throws InvalidXmlException;
}

View file

@ -0,0 +1,92 @@
package cr0s.warpdrive.config.filler;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.InvalidXmlException;
import cr0s.warpdrive.config.XmlRepresentable;
import net.minecraft.block.Block;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
/**
* Represents a single filler block.
**/
public class Filler implements XmlRepresentable {
private String name;
public Block block;
public int metadata;
public NBTTagCompound tag = null; // TODO
@Override
public String getName() {
return name;
}
public Filler() {
}
@Override
public boolean loadFromXmlElement(Element element) throws InvalidXmlException {
// Check there is a block name
if (!element.hasAttribute("block")) {
throw new InvalidXmlException("Filler " + element + " is missing a block tag!");
}
String blockName = element.getAttribute("block");
block = Block.getBlockFromName(blockName);
if (block == null) {
WarpDrive.logger.warn("Skipping missing block " + blockName);
return false;
}
// Get metadata attribute, defaults to 0
metadata = 0;
String stringMetadata = element.getAttribute("metadata");
if (!stringMetadata.isEmpty()) {
try {
metadata = Integer.parseInt(stringMetadata);
} catch (NumberFormatException exception) {
throw new InvalidXmlException("Invalid metadata for block " + blockName);
}
}
name = blockName + "@" + metadata + "{" + tag + "}";
return true;
}
/**
* @deprecated Not implemented
**/
@Deprecated
@Override
public void saveToXmlElement(Element element, Document document) throws InvalidXmlException {
throw new InvalidXmlException("Not implemented");
}
public void setBlock(World world, int x, int y, int z) {
world.setBlock(x, y, z, block, metadata, 2);
// TODO set NBT data
}
@Override
public boolean equals(Object object) {
return object instanceof Filler
&& (block == null || block.equals(((Filler)object).block))
&& metadata == ((Filler)object).metadata
&& (tag == null || tag.equals(((Filler)object).tag));
}
@Override
public String toString() {
return "Filler(" + block.getUnlocalizedName() + "@" + metadata + ")";
}
@Override
public int hashCode() {
return Block.getIdFromBlock(block) * 16 + metadata + (tag == null ? 0 : tag.hashCode() * 4096 * 16);
}
}

View file

@ -1,270 +0,0 @@
package cr0s.warpdrive.config.filler;
import java.util.Map.Entry;
import java.util.TreeMap;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.MetaBlock;
import net.minecraft.block.Block;
/**
* Used for constructing FillerSets from a combination of Weights and Ratios
*
*/
public class FillerFactory {
private TreeMap<MetaBlock, Integer> metaBlocksWeight;
private TreeMap<MetaBlock, Integer> convertedRatioMetaBlocks;
private int totalWeightNeeded;
private int totalWeightWeightedBlocks;
private Object lock;
//Used to keep track of added ratio blocks in case this factory is imported into another.
private TreeMap<MetaBlock, String> addedRatioMetaBlocks;
/**
* Initializes new FillerFactory
*/
public FillerFactory() {
lock = new Object();
init();
}
/**
* Clears all data and initializes needed arrays
*/
private void init() {
metaBlocksWeight = new TreeMap<MetaBlock, Integer>();
convertedRatioMetaBlocks = new TreeMap<MetaBlock, Integer>();
totalWeightNeeded = 0;
totalWeightWeightedBlocks = 0;
addedRatioMetaBlocks = new TreeMap<MetaBlock, String>();
}
/**
* Resets to how this factory was at the start, and ready to create a new FillerSet
*/
public void reset() {
init();
}
/**
* Convenience method which converts to a MetaBlock and then calls addWeightedMetaBlock
*
* @param b
* Block to add
* @param metadata
* Metadata to add
* @param weight
* Weight the block was given
*/
public void addWeightedBlock(Block b, int metadata, int weight) {
addWeightedMetaBlock(MetaBlock.getMetaBlock(b, metadata), weight);
}
/**
* Adds the given Meta Block as an originally weighted block.
*
* @param mb
* MetaBlock info to add
* @param weight
* The given weight of the block
*/
public void addWeightedMetaBlock(MetaBlock mb, int weight) {
metaBlocksWeight.put(mb, weight);
totalWeightWeightedBlocks += weight;
}
/**
* Convenience method which converts to a MetaBlock and then calls addRatioMetaBlock
*
* @param b
* Block to add
* @param metadata
* Block's metadata
* @param ratio
* The given ratio, in the original string form
*/
public void addRatioBlock(Block b, int metadata, String ratio) {
addRatioMetaBlock(MetaBlock.getMetaBlock(b, metadata), ratio);
}
/**
* Add a MetaBlock with the given ratio. Ratio should be convertible to a double.
*
* @param mb
* @param ratio
*/
public void addRatioMetaBlock(MetaBlock mb, String ratio) {
//In case of an import
addedRatioMetaBlocks.put(mb, ratio);
//Prevent this from being run twice at once
synchronized (lock) {
//Clean out anything unnecessary
ratio = ratio.trim();
//Make sure it is an actual number
if (Double.parseDouble(ratio) > 1)
throw new IllegalArgumentException("Ratio must be less than one");
//Get the position of the period, so that we can find the number of significant digits.
//This will probably be at 1
int lastDot = ratio.lastIndexOf('.');
int sigFig;
//Go through and check to find the actual last significant digit.
for (sigFig = ratio.length() - 1; sigFig > lastDot; sigFig--) {
if (ratio.charAt(sigFig) != '0')
break;
}
//Check to make sure there was an actual number.
if (sigFig <= lastDot)
throw new IllegalArgumentException("Ratio must be greater than zero");
int ratioInt = Integer.parseInt(ratio.substring(lastDot + 1, sigFig + 1));
//Weight needed should be a power of ten
int digits = sigFig - lastDot;
int weightNeeded = (int) Math.pow(10, digits);
//Check if the weight needed for accuracy is greater than all the ones until now
if (weightNeeded > totalWeightNeeded) {
//Calculate the extra powers needed by existing ratio MetaBlocks
int additionalPowersNeeded = totalWeightNeeded / weightNeeded;
//Convert them to the new standard
for (Entry<MetaBlock, Integer> entry : convertedRatioMetaBlocks.entrySet()) {
convertedRatioMetaBlocks.put(entry.getKey(), entry.getValue() * additionalPowersNeeded);
}
totalWeightNeeded = weightNeeded;
} else if (weightNeeded < totalWeightNeeded) { //The weight needed is less
//Calculate the extra powers needed by the new ratio MetaBlock
int additionalPowersNeeded = weightNeeded / totalWeightNeeded;
ratioInt *= additionalPowersNeeded;
}
convertedRatioMetaBlocks.put(mb, ratioInt);
}
}
/**
* Construct the actual array that should be used to generate random blocks
*
* @return A MetaBlock array
*/
public MetaBlock[] constructWeightedMetaBlockList() {
//Prevent this from being run twice at once
synchronized (lock) {
//If there are no ratios, convert directly to an array
if(convertedRatioMetaBlocks.isEmpty()) {
MetaBlock[] list = new MetaBlock[totalWeightWeightedBlocks];
int index = 0;
for (Entry<MetaBlock, Integer> entry : metaBlocksWeight.entrySet()) {
for (int i = 0; i < entry.getValue(); i++)
list[index++] = entry.getKey();
}
return list;
}
//Add up ratio weights
MetaBlock[] list = new MetaBlock[totalWeightNeeded];
int ratioTotalWeightUsed = 0;
int index = 0;
for (Entry<MetaBlock, Integer> entry : convertedRatioMetaBlocks.entrySet()) {
for (int i = 0; i < entry.getValue(); i++)
list[index++] = entry.getKey();
ratioTotalWeightUsed += entry.getValue();
}
int remainingWeight = totalWeightNeeded - ratioTotalWeightUsed;
if(remainingWeight < 0)
throw new IllegalArgumentException("Ratios add up to more than 100%");
if(remainingWeight == 0) {
WarpDrive.logger.info("Ratios add up perfectly to 100%, skipping weights");
} else {
//Add
//Add in weights
//There are two ways to do this.
//Option 1: Convert weighted Blocks to ratios compared to each other, and then get that ratio of the remaining
//Option 2: Treat the largest weight as a filler for unfilled places
//For now using option 1
//TODO: Make adjustable
for (Entry<MetaBlock, Integer> entry : metaBlocksWeight.entrySet()) {
int converted = entry.getValue() * remainingWeight / totalWeightWeightedBlocks;
for (int i = 0; i < converted; i++)
list[index++] = entry.getKey();
}
}
return list;
}
}
/**
* Add all the blocks previously added to the given factory to this factory
*
* @param factory
* Factory to get MetaBlocks from
*/
public void addFromFactory(FillerFactory factory) {
for (Entry<MetaBlock, String> addedBlock : factory.addedRatioMetaBlocks.entrySet())
addRatioMetaBlock(addedBlock.getKey(), addedBlock.getValue());
for (Entry<MetaBlock, Integer> addedBlock : factory.metaBlocksWeight.entrySet())
addWeightedMetaBlock(addedBlock.getKey(), addedBlock.getValue());
}
}

View file

@ -4,9 +4,9 @@ import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.Random;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -20,25 +20,13 @@ import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.config.XmlPreprocessor;
public class FillerManager {
// all fillerSets
private static HashMap<String, RandomCollection<FillerSet>> fillerSetsByGroup;
private static TreeMap<String, FillerSet> fillerSetsByName = new TreeMap<String, FillerSet>();
private static TreeMap<String, RandomCollection<FillerSet>> fillerSetsByGroup = new TreeMap<String, RandomCollection<FillerSet>>();
private static final String[] REQUIRED_GROUPS = { };
// Stores extra dependency information
static TreeMap<FillerSet, ArrayList<String>> fillerSetsDependencies = new TreeMap<FillerSet, ArrayList<String>>();
/* TODO dead code?
// FillerSets that are guaranteed to exist
public static final String COMMON_ORES = "commonOres";
public static final String UNCOMMON_ORES = "uncommonOres";
public static final String RARE_ORES = "rareOres";
public static final String OVERWORLD = "overworld";
public static final String NETHER = "nether";
public static final String END = "end";
/**/
public static void loadOres(File dir) {
// directory is created by caller, so it can copy default files if any
public static void load(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!");
@ -51,6 +39,7 @@ public class FillerManager {
}
});
fillerSetsByGroup = new HashMap<String, RandomCollection<FillerSet>>();
for(File file : files) {
try {
loadXmlFillerFile(file);
@ -59,6 +48,15 @@ public class FillerManager {
exception.printStackTrace();
}
}
for (String group : REQUIRED_GROUPS) {
if (!fillerSetsByGroup.containsKey(group)) {
WarpDrive.logger.error("Error: no fillerSet defined for mandatory group " + group);
}
}
propagateFillerSets();
WarpDrive.logger.info("Loading filler data files done");
}
@ -77,80 +75,80 @@ public class FillerManager {
XmlPreprocessor.doLogicPreprocessing(document);
// only add FillerSets
NodeList nodesFillerSet = document.getElementsByTagName("FillerSet");
for (int fillerSetIndex = 0; fillerSetIndex < nodesFillerSet.getLength(); fillerSetIndex++) {
NodeList nodeListFillerSet = document.getElementsByTagName("fillerSet");
for (int fillerSetIndex = 0; fillerSetIndex < nodeListFillerSet.getLength(); fillerSetIndex++) {
Element elementFillerSet = (Element) nodesFillerSet.item(fillerSetIndex);
Element elementFillerSet = (Element) nodeListFillerSet.item(fillerSetIndex);
String group = elementFillerSet.getAttribute("group");
if (group.isEmpty()) {
throw new InvalidXmlException("FillerSet " + (fillerSetIndex + 1) + "/" + nodesFillerSet.getLength() + " is missing a group attribute!");
throw new InvalidXmlException("FillerSet " + (fillerSetIndex + 1) + "/" + nodeListFillerSet.getLength() + " is missing a group attribute!");
}
String name = elementFillerSet.getAttribute("name");
if (name.isEmpty()) {
throw new InvalidXmlException("FillerSet " + (fillerSetIndex + 1) + "/" + nodesFillerSet.getLength() + " is missing a name attribute!");
throw new InvalidXmlException("FillerSet " + (fillerSetIndex + 1) + "/" + nodeListFillerSet.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);
if (WarpDriveConfig.LOGGING_WORLDGEN) {
WarpDrive.logger.info("- found FillerSet " + group + ":" + name);
}
RandomCollection randomCollection = fillerSetsByGroup.get(group);
RandomCollection<FillerSet> randomCollection = fillerSetsByGroup.get(group);
if (randomCollection == null) {
randomCollection = new RandomCollection<FillerSet>();
fillerSetsByGroup.put(group, randomCollection);
}
randomCollection.loadFromXML(fillerSet, elementFillerSet);
if (elementFillerSet.hasAttribute("fillerSets")) {
FillerSet fillerSet = randomCollection.getNamedEntry(name);
if (fillerSet == null) {
fillerSet = new FillerSet(group, name);
}
randomCollection.loadFromXML(fillerSet, elementFillerSet);
}
}
private static void propagateFillerSets() {
HashMap<FillerSet, ArrayList<String>> fillerSetsDependencies = new HashMap<FillerSet, ArrayList<String>>();
// scan for static import dependencies
for (RandomCollection<FillerSet> fillerSets : fillerSetsByGroup.values()) {
for (FillerSet fillerSet : fillerSets.elements()) {
ArrayList<String> dependencies = fillerSetsDependencies.get(fillerSet);
if (dependencies == null) {
dependencies = new ArrayList<String>();
fillerSetsDependencies.put(fillerSet, dependencies);
}
dependencies.addAll(Arrays.asList(elementFillerSet.getAttribute("fillerSets").split(",")));
dependencies.addAll(fillerSet.getImportGroupNames());
}
fillerSet.loadFromXmlElement(elementFillerSet);
}
}
public static void finishLoading() {
// import fillerSets into each others
propagateFillerSets();
// 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 propagateFillerSets() {
while (!fillerSetsDependencies.isEmpty()) {
TreeMap<FillerSet, ArrayList<String>> fillerSetsLeftToImport = new TreeMap<FillerSet, ArrayList<String>>();
// resolve
int iterationCount = 0;
while (!fillerSetsDependencies.isEmpty() && iterationCount++ < 10) {
HashMap<FillerSet, ArrayList<String>> fillerSetsLeftToImport = new HashMap<FillerSet, ArrayList<String>>();
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());
FillerSet fillerSet = getFillerSet(dependency);
if (fillerSet == null) {
WarpDrive.logger.error("Ignoring missing FillerSet " + dependency + " dependency in FillerSet " + entry.getKey());
} else if (fillerSetsDependencies.containsKey(fillerSetsByName.get(dependency))) {
} else if (fillerSetsDependencies.containsKey(fillerSet)) {
// skip until it is loaded
newDependencies.add(dependency);
} else {
entry.getKey().loadFrom(fillerSetsByName.get(dependency));
try {
if (WarpDriveConfig.LOGGING_WORLDGEN) {
WarpDrive.logger.info("Importing FillerSet " + fillerSet.getFullName() + " in " + entry.getKey().getFullName());
}
entry.getKey().loadFrom(fillerSet);
} catch (InvalidXmlException exception) {
exception.printStackTrace();
WarpDrive.logger.error("While importing " + dependency + " into FillerSet " + entry.getKey().getFullName());
}
}
}
if (!newDependencies.isEmpty()) {
@ -160,9 +158,42 @@ public class FillerManager {
fillerSetsDependencies = fillerSetsLeftToImport;
}
// recursion has reach the limit?
if (!fillerSetsDependencies.isEmpty()) {
WarpDrive.logger.error("Too many import recursions, ignoring the remaining ones:");
for (Entry<FillerSet, ArrayList<String>> entry : fillerSetsDependencies.entrySet()) {
WarpDrive.logger.warn("- FillerSet " + entry.getKey() + " is pending:");
for (String dependency : entry.getValue()) {
WarpDrive.logger.warn(" + " + dependency);
}
}
}
}
public static boolean doesFillerSetExist(String groupOrName) {
return fillerSetsByName.containsKey(groupOrName) || fillerSetsByName.containsKey(groupOrName);
public static boolean doesGroupExist(final String groupName) {
return fillerSetsByGroup.get(groupName) != null;
}
public static FillerSet getRandomFillerSetFromGroup(Random random, final String groupName) {
RandomCollection<FillerSet> group = fillerSetsByGroup.get(groupName);
if (group == null) {
return null;
}
FillerSet fillerSet = group.getRandomEntry(random);
return fillerSet;
}
public static FillerSet getFillerSet(final String groupAndName) {
String[] parts = groupAndName.split(":");
if (parts.length != 2) {
WarpDrive.logger.error("Invalid FillerSet '" + groupAndName + "'. Expecting '{group}:{name}'");
return null;
}
RandomCollection<FillerSet> group = fillerSetsByGroup.get(parts[0]);
if (group == null) {
return null;
}
return group.getNamedEntry(parts[1]);
}
}

View file

@ -1,32 +1,32 @@
package cr0s.warpdrive.config.filler;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
import net.minecraft.init.Blocks;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.InvalidXmlException;
import cr0s.warpdrive.config.MetaBlock;
import cr0s.warpdrive.config.RandomCollection;
import cr0s.warpdrive.config.XmlRepresentable;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
/**
* Represents a set of fillers. Before using after construction, finishContruction() must be called.
*
* If FillerSet(blocks[]) is called, that is not necessary.
*
*/
* Represents a set of fillers.
**/
public class FillerSet implements XmlRepresentable, Comparable {
private MetaBlock[] weightedFillerBlocks;
private FillerFactory factory;
protected String group;
protected String name;
private RandomCollection<Filler> fillers;
private ArrayList<String> importGroupNames;
private ArrayList<String> importGroups;
public String getGroup() {
return group;
public String getFullName() {
return group + ":" + name;
}
@Override
@ -34,94 +34,58 @@ public class FillerSet implements XmlRepresentable, Comparable {
return name;
}
public FillerSet(MetaBlock[] blocks) {
weightedFillerBlocks = blocks;
}
public FillerSet(final String group, final String name) {
this.group = group;
this.name = name;
weightedFillerBlocks = new MetaBlock[1];
factory = new FillerFactory();
fillers = new RandomCollection<Filler>();
importGroupNames = new ArrayList<String>();
importGroups = new ArrayList<String>();
}
public MetaBlock getRandomBlock(Random rand) {
return weightedFillerBlocks[rand.nextInt(weightedFillerBlocks.length)];
public boolean isEmpty() {
return fillers.isEmpty();
}
public Filler getRandomBlock(Random random) {
Filler filler = fillers.getRandomEntry(random);
if (filler == null) {
WarpDrive.logger.error("null filler encountered in FillerSet " + getFullName());
filler = new Filler();
filler.block = Blocks.glass;
}
return filler;
}
@Override
public void loadFromXmlElement(Element element) throws InvalidXmlException {
public boolean loadFromXmlElement(Element element) throws InvalidXmlException {
NodeList nodeListFillers = element.getElementsByTagName("filler");
for (int i = 0; i < nodeListFillers.getLength(); i++) {
Element elementFiller = (Element) nodeListFillers.item(i);
Filler filler = new Filler();
fillers.loadFromXML(filler, elementFiller);
}
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");
if (!stringMetadata.isEmpty()) {
try {
intMetadata = Integer.parseInt(stringMetadata);
} catch (NumberFormatException exception) {
throw new InvalidXmlException("Invalid metadata for block " + blockName);
NodeList nodeListImports = element.getElementsByTagName("import");
if (nodeListImports.getLength() > 0) {
for (int importIndex = 0; importIndex < nodeListImports.getLength(); importIndex++) {
Element elementImport = (Element) nodeListImports.item(importIndex);
String importGroup = elementImport.getAttribute("group");
String importName = elementImport.getAttribute("name");
if (!importGroup.isEmpty()) {
if (!importName.isEmpty()) {
importGroupNames.add(importGroup + ":" + importName);
} else {
importGroups.add(importGroup);
}
} else {
WarpDrive.logger.warn("Ignoring import with no group definition in import element from " + getFullName());
}
}
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);
}
}
return true;
}
/**
@ -133,25 +97,6 @@ public class FillerSet implements XmlRepresentable, Comparable {
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()
*
* Clears the memory used for construction
*/
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 FIXME
for (int i = 0; i < weightedFillerBlocks.length; i++) {
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);
@ -159,16 +104,34 @@ public class FillerSet implements XmlRepresentable, Comparable {
@Override
public String toString() {
return name;
return getFullName() + "(" + (fillers == null ? "-empty-" : fillers.elements().size()) + ")";
}
/**
* Adds the blocks from the given fillerSet into this one. Must be pre-finishConstruction()
*
* @param fillerSet
* The fillerset to add from
* The fillerSet to add from
*/
public void loadFrom(FillerSet fillerSet) {
factory.addFromFactory(fillerSet.factory);
public void loadFrom(FillerSet fillerSet) throws InvalidXmlException {
fillers.loadFrom(fillerSet.fillers);
}
/**
* Return static import dependencies
*
* @return null or a list of group:names to be imported
**/
public Collection<String> getImportGroupNames() {
return importGroupNames;
}
/**
* Return dynamic import dependencies
*
* @return null or a list of groups to be imported
**/
public Collection<String> getImportGroups() {
return importGroups;
}
}

View file

@ -0,0 +1,90 @@
/**
*
*/
package cr0s.warpdrive.config.structures;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Random;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.gen.feature.WorldGenerator;
/**
* @author LemADEC
*
*/
public abstract class AbstractInstance extends WorldGenerator {
protected AbstractStructure structure;
protected HashMap<String,Double> variables = new HashMap<String,Double>();
public AbstractInstance(AbstractStructure structure, Random random) {
this.structure = structure;
// evaluate variables
for (Entry<String, String> entry : structure.variables.entrySet()) {
double value = Double.NaN;
String stringValue = entry.getValue();
try {
if (stringValue.contains(",")) {
String[] values = stringValue.split(",");
stringValue = values[random.nextInt(values.length)];
}
value = Double.parseDouble(entry.getValue());
} catch (NumberFormatException exception) {
throw new RuntimeException("Invalid expression '" + entry.getValue() + "'"
+ (stringValue.equalsIgnoreCase(entry.getValue()) ? "" : " in '" + entry.getValue() + "'")
+ " for variable " + entry.getKey()
+ " in deployable structure " + structure.name
+ ": a numeric value is expected. Check the related XML configuration file...");
}
variables.put(entry.getKey(), value);
}
}
protected static int randomRange(Random random, final int min, final int max) {
return min + ((max - min > 0) ? random.nextInt(max - min + 1) : 0);
}
protected static double randomRange(Random random, final double min, final double max) {
return min + ((max - min > 0) ? random.nextDouble() * (max - min) : 0);
}
protected String evaluate(final String valueOrExpression) {
if (!valueOrExpression.contains("%")) {
return valueOrExpression;
}
String result = valueOrExpression;
for (Entry<String, Double> variable : variables.entrySet()) {
result = result.replaceAll(variable.getKey(), "" + variable.getValue());
}
return result;
}
public AbstractInstance(NBTTagCompound tag) {
// FIXME to be implemented
// get deployable
// String deployableName = tag.getString("wd_structureName");
// get variables values
/*
NBTTagCompound tagVariables = tag.getCompoundTag("wd_variables");
NBTTagList names = tagVariables.getTagList("x", 0);
for (Entry<String, Double> entry : tagVariables.getTagList("x", 0)) {
tagVariables.setDouble(entry.getKey(), entry.getValue());
}
/**/
}
public void WriteToNBT(NBTTagCompound tag) {
tag.setString("wd_structureGroup", structure.group);
tag.setString("wd_structureName", structure.name);
NBTTagCompound tagVariables = new NBTTagCompound();
for (Entry<String, Double> entry : variables.entrySet()) {
tagVariables.setDouble(entry.getKey(), entry.getValue());
}
tag.setTag("wd_variables", tagVariables);
}
}

View file

@ -0,0 +1,65 @@
/**
*
*/
package cr0s.warpdrive.config.structures;
import java.util.HashMap;
import java.util.Random;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import cr0s.warpdrive.config.InvalidXmlException;
import cr0s.warpdrive.config.XmlRepresentable;
import net.minecraft.world.gen.feature.WorldGenerator;
/**
* @author Francesco, LemADEC
*
*/
public abstract class AbstractStructure extends WorldGenerator implements XmlRepresentable {
protected String group;
protected String name;
protected HashMap<String,String> variables = new HashMap<String,String>();
public AbstractStructure(final String group, final String name) {
this.group = group;
this.name = name;
}
@Override
public String getName() {
return name;
}
public String getFullName() {
return group + ":" + name;
}
abstract public AbstractInstance instantiate(Random random);
@Override
public boolean loadFromXmlElement(Element element) throws InvalidXmlException {
NodeList nodeListVariables = element.getElementsByTagName("variable");
for (int variableIndex = 0; variableIndex < nodeListVariables.getLength(); variableIndex++) {
Element elementVariable = (Element) nodeListVariables.item(variableIndex);
String variableName = elementVariable.getAttribute("name");
String variableExpression = elementVariable.getTextContent();
variables.put(variableName, variableExpression);
}
return true;
}
/**
* @deprecated Not implemented
**/
@Deprecated
@Override
public void saveToXmlElement(Element element, Document document) throws InvalidXmlException {
throw new InvalidXmlException("Not implemented");
}
}

View file

@ -1,194 +0,0 @@
package cr0s.warpdrive.config.structures;
import java.util.ArrayList;
import java.util.Random;
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 CORE_MAX_TRIES = 10;
private Block coreBlock;
private int maxCoreCount;
private int minCoreCount;
private double relativeCoreRadius;
public Asteroid(final String name) {
super(name);
}
@Override
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 " + name + " has an invalid/missing coreBlock " + coreBlockName);
}
try {
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 {
relativeCoreRadius = Double.parseDouble(element.getAttribute("relativeCoreRadius"));
}
} catch (NumberFormatException gdbg) {
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 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 location Location of core block
* @param maxRad Maximum radius of asteroid
*/
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 range = (int)Math.round(Math.sqrt(dX2Y2 + (location.z - z) * (location.z - z)));
// if inside radius
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);
}
}
}
}
}
/**
* Checks if given coordinate empty (air in terms of MC).
* @param world
* @param x
* @param y
* @param z
* @return
*/
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);
}
/**
* Generates core with simplified algorithm that tries to place numberOfBlocks cores within a core sphere (specified in config by "coreRad" value from 0.0 to 1.0).
*
* Note: CORE_MAX_TRIES defines how many tries the method applies before giving up placing a core.
*
* @param world - World where to place cores
* @param rand - Random generator
* @param x - center X coord
* @param y - center Y coord
* @param z - center Z coord
* @param numberOfBlocks - number of core blocks to place
* @param block - type of block to place
* @param metadata - metadata of bloeck to place
* @param coreRadius - max radius of asteroid
* @return List of placed locations of cores
*/
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 coreBlockIndex = 0; coreBlockIndex < numberOfBlocks; coreBlockIndex++) {
int curX = x;
int curY = y;
int curZ = z;
boolean found = false;
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 (isReplaceableOreGen(world, curX, curY, curZ)) {
world.setBlock(curX, curY, curZ, block, metadata, 2);
addedBlocks.add(new VectorI(curX, curY, curZ));
found = true;
}
}
}
return addedBlocks;
}
}

View file

@ -1,34 +0,0 @@
/**
*
*/
package cr0s.warpdrive.config.structures;
import net.minecraft.world.gen.feature.WorldGenerator;
/**
* @author Francesco, LemADEC
*
*/
public abstract class DeployableStructure extends WorldGenerator {
protected String name;
protected int sizeX;
protected int sizeY;
protected int sizeZ;
public DeployableStructure(final String name) {
this.name = name;
}
public void setDimensions(final int sizeX, final int sizeY, final int sizeZ) {
this.sizeX = sizeX;
this.sizeY = sizeY;
this.sizeZ = sizeZ;
}
public void setRadius(final int radius) {
sizeX = radius * 2;
sizeY = radius * 2;
sizeZ = radius * 2;
}
}

View file

@ -0,0 +1,165 @@
package cr0s.warpdrive.config.structures;
import java.util.Random;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.InvalidXmlException;
import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.config.XmlRepresentable;
import net.minecraft.block.Block;
import net.minecraft.world.World;
public class MetaOrb extends Orb {
protected Metashell metashell;
public MetaOrb(final String group, final String name) {
super(group, name);
}
@Override
public boolean loadFromXmlElement(Element element) throws InvalidXmlException {
super.loadFromXmlElement(element);
NodeList nodeListMetashells = element.getElementsByTagName("metashell");
if (nodeListMetashells.getLength() > 1) {
throw new InvalidXmlException("Too many metashell defined in structure " + getFullName() + ". Maximum is 1.");
}
if (nodeListMetashells.getLength() == 1) {
metashell = new Metashell(getFullName());
metashell.loadFromXmlElement((Element) nodeListMetashells.item(0));
}
return true;
}
@Override
public boolean generate(World world, Random random, int x, int y, int z) {
return instantiate(random).generate(world, random, x, y, z);
}
@Override
public AbstractInstance instantiate(Random random) {
return new MetaOrbInstance(this, random);
}
public class Metashell implements XmlRepresentable {
private String parentFullName;
protected Block block;
protected int metadata;
protected int minCount;
protected int maxCount;
protected double minRadius;
protected double relativeRadius;
public Metashell(final String parentFullName) {
this.parentFullName = parentFullName;
}
@Override
public String getName() {
return "metashell";
}
@Override
public boolean loadFromXmlElement(Element element) throws InvalidXmlException {
if (WarpDriveConfig.LOGGING_WORLDGEN) {
WarpDrive.logger.info(" + found metashell");
}
String stringValue;
// block & metadata
stringValue = element.getAttribute("block");
if (!stringValue.isEmpty()) {
block = Block.getBlockFromName(stringValue);
if (block == null) {
WarpDrive.logger.warn("Skipping missing metashell core block " + stringValue + " in " + parentFullName);
} else {
// metadata
stringValue = element.getAttribute("metadata");
if (stringValue.isEmpty()) {
metadata = 0;
} else {
try {
metadata = Integer.parseInt(stringValue);
} catch (NumberFormatException exception) {
throw new InvalidXmlException("Structure " + parentFullName + " has an invalid metadata " + stringValue + ", expecting an integer");
}
}
if (metadata < 0 || metadata > 15) {
throw new InvalidXmlException("Structure " + parentFullName + " has an invalid metadata " + metadata + ", expecting a value between 0 and 15 included");
}
}
}
// count
try {
minCount = Integer.parseInt(element.getAttribute("minCount"));
} catch (NumberFormatException exception) {
throw new InvalidXmlException("Structure " + parentFullName + " has an invalid minCount " + element.getAttribute("minCount") + ", expecting an integer");
}
if (minCount < 1) {
throw new InvalidXmlException("Structure " + parentFullName + " has an invalid minCount " + minCount + ", expecting greater then 0");
}
try {
maxCount = Integer.parseInt(element.getAttribute("maxCount"));
} catch (NumberFormatException exception) {
throw new InvalidXmlException("Structure " + parentFullName + " has an invalid maxCount " + element.getAttribute("maxCount") + ", expecting an integer");
}
if (maxCount < minCount) {
throw new InvalidXmlException("Structure " + parentFullName + " has an invalid maxCount " + maxCount + ", expecting greater than or equal to minCount " + minCount);
}
// radius
try {
stringValue = element.getAttribute("minRadius");
if (stringValue.isEmpty()) {
minRadius = 2;
} else {
minRadius = Double.parseDouble(element.getAttribute("minRadius"));
}
} catch (NumberFormatException gdbg) {
throw new InvalidXmlException("Structure " + parentFullName + " has an invalid minRadius " + element.getAttribute("minRadius") + ", expecting a double");
}
if (minRadius < 0.0D || minRadius > 20.0D) {
throw new InvalidXmlException("Structure " + parentFullName + " has an invalid minRadius " + minRadius + ", expecting a value between 0.0 and 20.0 included");
}
try {
stringValue = element.getAttribute("relativeRadius");
if (stringValue.isEmpty()) {
relativeRadius = 0.5;
} else {
relativeRadius = Double.parseDouble(element.getAttribute("relativeRadius"));
}
} catch (NumberFormatException gdbg) {
throw new InvalidXmlException("Structure " + parentFullName + " has an invalid relativeRadius " + element.getAttribute("relativeRadius") + ", expecting a double");
}
if (relativeRadius < 0.0D || relativeRadius > 2.0D) {
throw new InvalidXmlException("Structure " + parentFullName + " has an invalid relativeRadius " + relativeRadius + ", expecting a value between 0.0 and 2.0 included");
}
return true;
}
/**
* @deprecated Not implemented
**/
@Deprecated
@Override
public void saveToXmlElement(Element element, Document document) throws InvalidXmlException {
throw new InvalidXmlException("Not implemented");
}
}
}

View file

@ -0,0 +1,147 @@
package cr0s.warpdrive.config.structures;
import java.util.ArrayList;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.world.World;
import cr0s.warpdrive.LocalProfiler;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.config.filler.Filler;
import cr0s.warpdrive.config.structures.Orb.OrbShell;
import cr0s.warpdrive.data.VectorI;
public class MetaOrbInstance extends OrbInstance {
private static final int CORE_MAX_TRIES = 10;
protected Metashell metashell;
public MetaOrbInstance(MetaOrb asteroid, Random random) {
super(asteroid, random);
metashell = new Metashell(asteroid, random);
// FIXME setRadius(Math.round(totalThickness + metashell.radius));
}
@Override
public boolean generate(World world, Random random, int x, int y, int z) {
if (WarpDriveConfig.LOGGING_WORLDGEN) {
WarpDrive.logger.info("Generating MetaOrb " + structure.name + " of " + metashell.count + " cores with radius of " + totalThickness);
}
LocalProfiler.start("[AsteroidInstance] Generating MetaOrb " + structure.name + " of " + metashell.count + " cores with radius of " + totalThickness);
if (((MetaOrb)structure).metashell == null) {
return super.generate(world, random, x, y, z);
}
// generate an abstract form for the core
for (VectorI location: metashell.locations) {
// place core block
if (metashell.block != null) {
world.setBlock(x + location.x, y + location.y, z + location.z, metashell.block, metashell.metadata, 2);
}
// calculate distance to borders of generation area
int maxRadX = totalThickness - Math.abs(location.x);
int maxRadY = totalThickness - Math.abs(location.y);
int maxRadZ = totalThickness - Math.abs(location.z);
// keep the biggest one to have a bumpy effect
int maxLocalRadius = Math.max(maxRadX, Math.max(maxRadY, maxRadZ));
// enforce a minimum thickness to prevent lone core blocks
// (see case where core radius is close to totalThickness)
maxLocalRadius = Math.max(minThickness, maxLocalRadius);
// Generate shell
addShell(world, new VectorI(x, y, z).add(location), maxLocalRadius);
}
LocalProfiler.stop();
return false;
}
/**
* Creates a shell sphere around given core location.
*
* @param thicknesses Random generator
* @param world World to place shell
* @param location Location of core block
* @param maxRad Maximum radius of asteroid
*/
private void addShell(World world, VectorI location, int radius) {
double sqRadius = radius * 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 sqRange = dX2Y2 + (location.z - z) * (location.z - z);
// if inside radius
if (sqRange <= sqRadius && isReplaceableOreGen(world, x, y, z)) {
OrbShell shell = getShellForSqRadius(sqRange);
Filler filler = shell.getRandomBlock(world.rand);
filler.setBlock(world, x, y, z);
}
}
}
}
}
/**
* Checks if given coordinate empty (air in terms of MC).
* @param world
* @param x
* @param y
* @param z
* @return
*/
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);
}
public class Metashell {
protected int count;
protected double radius;
protected ArrayList<VectorI> locations;
protected Block block;
protected int metadata;
public Metashell(MetaOrb asteroid, Random random) {
if (asteroid.metashell == null) {
count = 1;
radius = 0;
block = null;
metadata = 0;
return;
}
count = randomRange(random, asteroid.metashell.minCount, asteroid.metashell.maxCount);
radius = Math.max(asteroid.metashell.minRadius, asteroid.metashell.relativeRadius * totalThickness);
block = asteroid.metashell.block;
metadata = asteroid.metashell.metadata;
// evaluate core positions
locations = new ArrayList<VectorI>();
double diameter = Math.max(1D, 2 * radius);
double xMin = -radius;
double yMin = -radius;
double zMin = -radius;
for (int index = 0; index < count; index++) {
boolean found = false;
for(int step = 0; step < CORE_MAX_TRIES && !found; step++) {
VectorI location = new VectorI(
(int)Math.round(xMin + diameter * random.nextDouble()),
(int)Math.round(yMin + diameter * random.nextDouble()),
(int)Math.round(zMin + diameter * random.nextDouble()));
if (!locations.contains(location)) {
locations.add(location);
found = true;
}
}
}
}
}
}

View file

@ -1,156 +1,153 @@
package cr0s.warpdrive.config.structures;
import java.util.ArrayList;
import java.util.Random;
import net.minecraft.world.World;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.InvalidXmlException;
import cr0s.warpdrive.config.XmlRepresentable;
import cr0s.warpdrive.config.WarpDriveConfig;
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 {
public class Orb extends AbstractStructure {
private OrbShell[] orbShells;
protected OrbShell[] orbShells;
protected boolean hasStarCore = false;
private ArrayList<String> fillerSetGroupOrNames = new ArrayList<String>();
protected String schematicName;
public Orb(final String name) {
super(name);
public Orb(final String group, final String name) {
super(group, name);
}
@Override
public String getName() {
return name;
}
@Override
public void loadFromXmlElement(Element element) throws InvalidXmlException {
int maxThickness = 0;
public boolean loadFromXmlElement(Element element) throws InvalidXmlException {
super.loadFromXmlElement(element);
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");
int shellIndexOut = 0;
for (int shellIndexIn = 0; shellIndexIn < nodeListShells.getLength(); shellIndexIn++) {
Element elementShell = (Element) nodeListShells.item(shellIndexIn);
String orbShellName = elementShell.getAttribute("name");
orbShells[shellIndex] = new OrbShell(name, orbShellName);
orbShells[shellIndex].loadFromXmlElement(elementShell);
orbShells[shellIndex].finishContruction();
maxThickness += orbShells[shellIndex].maxThickness;
orbShells[shellIndexOut] = new OrbShell(getFullName(), orbShellName);
try {
orbShells[shellIndexOut].loadFromXmlElement(elementShell);
shellIndexOut++;
} catch (InvalidXmlException exception) {
exception.printStackTrace();
WarpDrive.logger.error("Skipping invalid shell " + orbShellName);
}
}
setRadius(maxThickness - 1);
}
/**
* @deprecated Not implemented
**/
@Deprecated
@Override
public void saveToXmlElement(Element element, Document document) throws InvalidXmlException {
throw new InvalidXmlException("Not implemented");
NodeList nodeListSchematic = element.getElementsByTagName("schematic");
if (nodeListSchematic.getLength() > 1) {
WarpDrive.logger.error("Too many schematic defined, only first one will be used in structure " + getFullName());
}
if (nodeListSchematic.getLength() > 0) {
schematicName = ((Element)nodeListSchematic.item(0)).getAttribute("group");
}
return true;
}
@Override
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;
}
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;
return instantiate(random).generate(world, random, x, y, z);
}
/**
*
* @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, this, null, radius, true);
world.spawnEntityInWorld(entitySphereGen);
return false;
}
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;
@Override
public AbstractInstance instantiate(Random random) {
return new OrbInstance(this, random);
}
public class OrbShell extends FillerSet {
private String parentName;
private int minThickness;
private int maxThickness;
private String parentFullName;
protected int minThickness;
protected int maxThickness;
public OrbShell(String parentName, String name) {
public OrbShell(final String parentFullName, final String name) {
super(null, name);
this.parentName = parentName;
this.parentFullName = parentFullName;
}
@Override
public void loadFromXmlElement(Element element) throws InvalidXmlException {
WarpDrive.logger.info("Loading shell " + element.getAttribute("name"));
public boolean loadFromXmlElement(Element element) throws InvalidXmlException {
if (WarpDriveConfig.LOGGING_WORLDGEN) {
WarpDrive.logger.info(" + found shell " + element.getAttribute("name"));
}
super.loadFromXmlElement(element);
if (element.hasAttribute("fillerSets")) {
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);
}
// resolve static imports
for (String importGroupName : getImportGroupNames()) {
FillerSet fillerSet = FillerManager.getFillerSet(importGroupName);
if (fillerSet == null) {
WarpDrive.logger.warn("Skipping missing FillerSet " + importGroupName + " in shell " + parentFullName + ":" + name);
} else {
loadFrom(fillerSet);
}
}
// validate dynamic imports
for (String importGroup : getImportGroups()) {
if (!FillerManager.doesGroupExist(importGroup)) {
WarpDrive.logger.warn("An invalid FillerSet group " + importGroup + " is referenced in shell " + parentFullName + ":" + name);
}
}
// shell thickness
try {
minThickness = Integer.parseInt(element.getAttribute("minThickness"));
} catch (NumberFormatException ex) {
throw new InvalidXmlException("Invalid minThickness in shell " + name + " of orb " + parentName);
} catch (NumberFormatException exception) {
throw new InvalidXmlException("Invalid minThickness in shell " + name + " of structure " + parentFullName);
}
try {
maxThickness = Integer.parseInt(element.getAttribute("maxThickness"));
} catch (NumberFormatException ex) {
throw new InvalidXmlException("Invalid maxThickness in shell " + name + " of orb " + parentName);
} catch (NumberFormatException exception) {
throw new InvalidXmlException("Invalid maxThickness in shell " + name + " of structure " + parentFullName);
}
if (maxThickness < minThickness) {
throw new InvalidXmlException("Invalid maxThickness " + maxThickness + " lower than minThickness " + minThickness + " in shell " + name + " of orb " + parentName);
throw new InvalidXmlException("Invalid maxThickness " + maxThickness + " lower than minThickness " + minThickness + " in shell " + name + " of orb " + parentFullName);
}
return true;
}
public OrbShell instantiate(Random random) {
OrbShell orbShell = new OrbShell(parentFullName, name);
orbShell.minThickness = minThickness;
orbShell.maxThickness = maxThickness;
try {
orbShell.loadFrom(this);
for (String importGroup : getImportGroups()) {
FillerSet fillerSet = FillerManager.getRandomFillerSetFromGroup(random, importGroup);
if (fillerSet == null) {
WarpDrive.logger.info("Ignoring invalid group " + importGroup + " in shell " + name + " of structure " + parentFullName);
continue;
}
if (WarpDriveConfig.LOGGING_WORLDGEN) {
WarpDrive.logger.info("Filling " + parentFullName + ":" + name + " with " + importGroup + ":" + fillerSet.getName());
}
orbShell.loadFrom(fillerSet);
}
} catch (InvalidXmlException exception) {
exception.printStackTrace();
WarpDrive.logger.error("Failed to instantiate shell " + name + " from structure " + parentFullName);
}
if (orbShell.isEmpty()) {
if (WarpDriveConfig.LOGGING_WORLDGEN) {
WarpDrive.logger.info("Ignoring empty shell " + name + " in structure " + parentFullName + "");
}
return null;
}
return orbShell;
}
}
}

View file

@ -0,0 +1,93 @@
package cr0s.warpdrive.config.structures;
import java.util.Random;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import cr0s.warpdrive.config.structures.Orb.OrbShell;
import cr0s.warpdrive.world.EntitySphereGen;
import cr0s.warpdrive.world.EntityStarCore;
import cr0s.warpdrive.world.WorldGenSmallShip;
public class OrbInstance extends AbstractInstance {
protected OrbShell[] orbShells;
protected int[] orbShellThicknesses;
protected int totalThickness;
protected int minThickness;
protected String schematicName;
// internal look-up table to accelerate computations
private OrbShell[] sqRadiusToOrbShell;
public OrbInstance(Orb orb, Random random) {
super(orb, random);
orbShells = new OrbShell[orb.orbShells.length];
orbShellThicknesses = new int[orb.orbShells.length];
totalThickness = 0;
minThickness = 0;
int orbShellIndexOut = 0;
for(int orbShellIndexIn = 0; orbShellIndexIn < orb.orbShells.length; orbShellIndexIn++) {
OrbShell orbShell = orb.orbShells[orbShellIndexIn].instantiate(random);
if (orbShell != null) {
orbShells[orbShellIndexOut] = orbShell;
int thickness = randomRange(random, orbShell.minThickness, orbShell.maxThickness);
orbShellThicknesses[orbShellIndexOut] = thickness;
totalThickness += thickness;
minThickness += orbShell.minThickness;
orbShellIndexOut++;
}
}
sqRadiusToOrbShell = new OrbShell[totalThickness * totalThickness];
for(int sqRadius = 0; sqRadius < sqRadiusToOrbShell.length; sqRadius++) {
int cumulatedRange = 0;
for (int shellIndex = 0; shellIndex < orbShells.length; shellIndex++) {
cumulatedRange += orbShellThicknesses[shellIndex];
if (sqRadius <= cumulatedRange * cumulatedRange) {
sqRadiusToOrbShell[sqRadius] = orbShells[shellIndex];
break;
}
}
}
schematicName = orb.schematicName;
}
public OrbInstance(NBTTagCompound tag) {
super(tag);
// TODO not implemented
}
@Override
public void WriteToNBT(NBTTagCompound tag) {
super.WriteToNBT(tag);
// TODO not implemented
}
public int getTotalThickness() {
return totalThickness;
}
@Override
public boolean generate(World world, Random random, int x, int y, int z) {
boolean hasShip = schematicName != null && !schematicName.isEmpty();
if (hasShip) {
new WorldGenSmallShip(false).generate(world, random, x, y, z);
}
EntitySphereGen entitySphereGen = new EntitySphereGen(world, x, y, z, this, !hasShip);
world.spawnEntityInWorld(entitySphereGen);
if (((Orb)structure).hasStarCore) {
return world.spawnEntityInWorld(new EntityStarCore(world, x, y, z, totalThickness));
}
return true;
}
public OrbShell getShellForSqRadius(final double sqRadius) {
int intSqRadius = (int)Math.round(sqRadius);
if (intSqRadius < sqRadiusToOrbShell.length) {
return sqRadiusToOrbShell[intSqRadius];
} else {
return sqRadiusToOrbShell[sqRadiusToOrbShell.length - 1];
}
}
}

View file

@ -1,7 +0,0 @@
package cr0s.warpdrive.config.structures;
public class Planetoid extends Orb {
public Planetoid(final String name) {
super(name);
}
}

View file

@ -4,11 +4,10 @@ import java.util.Random;
import net.minecraft.world.World;
public class SchematicStructure extends DeployableStructure {
public class Schematic extends AbstractStructure {
public SchematicStructure(final String name) {
super(name);
// TODO Auto-generated constructor stub
public Schematic(final String group, final String name) {
super(group, name);
}
@Override
@ -16,5 +15,10 @@ public class SchematicStructure extends DeployableStructure {
// TODO Auto-generated method stub
return false;
}
@Override
public AbstractInstance instantiate(Random random) {
// TODO Auto-generated method stub
return null;
}
}

View file

@ -2,8 +2,8 @@ package cr0s.warpdrive.config.structures;
public class Star extends Orb {
public Star(final String name) {
super(name);
public Star(final String group, final String name) {
super(group, name);
hasStarCore = true;
}
}

View file

@ -3,8 +3,10 @@ package cr0s.warpdrive.config.structures;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Random;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
@ -22,13 +24,14 @@ public class StructureManager {
public static final String GROUP_MOONS = "moon";
public static final String GROUP_GASCLOUDS = "gascloud";
public static final String GROUP_ASTEROIDS = "asteroid";
public static final String GROUP_ASTFIELDS_BIG = "astfield_big";
public static final String GROUP_ASTFIELDS_SMALL = "astfield_small";
private static RandomCollection<Star> stars = new RandomCollection<Star>();
private static RandomCollection<Planetoid> moons = new RandomCollection<Planetoid>();
private static RandomCollection<Asteroid> gasClouds = new RandomCollection<Asteroid>();
private static RandomCollection<Asteroid> asteroids = new RandomCollection<Asteroid>();
private static HashMap<String, RandomCollection<AbstractStructure>> structuresByGroup;
public static void loadStructures(File dir) {
private static final String[] REQUIRED_GROUPS = { GROUP_STARS, GROUP_MOONS, GROUP_GASCLOUDS, GROUP_ASTEROIDS, GROUP_ASTFIELDS_BIG, GROUP_ASTFIELDS_SMALL };
public static void load(File dir) {
dir.mkdir();
if (!dir.isDirectory()) {
@ -42,6 +45,7 @@ public class StructureManager {
}
});
structuresByGroup = new HashMap<String, RandomCollection<AbstractStructure>>();
for (File file : files) {
try {
loadXmlStructureFile(file);
@ -50,16 +54,24 @@ public class StructureManager {
exception.printStackTrace();
}
}
for (String group : REQUIRED_GROUPS) {
if (!structuresByGroup.containsKey(group)) {
WarpDrive.logger.error("Error: no structure defined for mandatory group " + group);
}
}
WarpDrive.logger.info("Loading structure data files done");
}
private static void loadXmlStructureFile(File file) throws SAXException, IOException, InvalidXmlException {
private static void loadXmlStructureFile(File file) throws InvalidXmlException, SAXException, IOException {
WarpDrive.logger.info("Loading structure data file " + file.getName());
Document document = WarpDriveConfig.getXmlDocumentBuilder().parse(file);
// pre-process the file
String result = XmlPreprocessor.checkModRequirements(document.getDocumentElement());
if (!result.isEmpty()) {
WarpDrive.logger.info("Skipping structure " + file.getName() + " due to " + result);
WarpDrive.logger.info("Skipping structure data file " + file.getName() + " due to " + result);
return;
}
@ -82,68 +94,54 @@ public class StructureManager {
throw new InvalidXmlException("Structure " + (structureIndex + 1) + "/" + nodeListStructures.getLength() + " is missing a name attribute!");
}
WarpDrive.logger.info("- found structure " + group + ":" + name);
WarpDrive.logger.info("- found Structure " + group + ":" + name);
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;
RandomCollection<AbstractStructure> randomCollection = structuresByGroup.get(group);
if (randomCollection == null) {
randomCollection = new RandomCollection<AbstractStructure>();
structuresByGroup.put(group, randomCollection);
}
AbstractStructure abstractStructure = randomCollection.getNamedEntry(name);
if (abstractStructure == null) {
if (group.equals(GROUP_STARS)) {
abstractStructure = new Star(group, name);
} else if (group.equals(GROUP_MOONS)) {
abstractStructure = new Orb(group, name);
} else {
abstractStructure = new MetaOrb(group, name);
}
}
randomCollection.loadFromXML(abstractStructure, elementStructure);
}
}
public static DeployableStructure getStructure(Random random, final String group, final String name) {
if (name == null || name.length() == 0) {
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 {
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);
}
public static AbstractStructure getStructure(Random random, final String group, final String name) {
if (group == null || group.isEmpty()) {
return null;
}
// not found or nothing defined
return null;
RandomCollection<AbstractStructure> randomCollection = structuresByGroup.get(group);
if (randomCollection == null) {
return null;
}
if (name == null || name.length() == 0) {
return randomCollection.getRandomEntry(random);
} else {
return randomCollection.getNamedEntry(name);
}
}
public static DeployableStructure getStar(Random random, final String name) {
return getStructure(random, GROUP_STARS, name);
}
public static DeployableStructure getMoon(Random random, final String name) {
return getStructure(random, GROUP_MOONS, name);
}
public static DeployableStructure getAsteroid(Random random, final String name) {
return getStructure(random, GROUP_ASTEROIDS, name);
}
public static DeployableStructure getGasCloud(Random random, final String name) {
return getStructure(random, GROUP_GASCLOUDS, name);
public static String getStructureNames(final String group) {
if (group == null || group.isEmpty()) {
// no operation
} else {
RandomCollection<AbstractStructure> randomCollection = structuresByGroup.get(group);
if (randomCollection != null) {
return randomCollection.getNames();
}
}
return "Error: group '" + group + "' isn't defined. Try one of: " + StringUtils.join(structuresByGroup.keySet(), ", ");
}
}

View file

@ -13,6 +13,7 @@ import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.config.filler.Filler;
public class JumpBlock {
public Block block;
@ -46,6 +47,19 @@ public class JumpBlock {
this.z = z;
}
public JumpBlock(Filler filler, int x, int y, int z) {
if (filler.block == null) {
WarpDrive.logger.info("Forcing glass for invalid filler with null block at " + x + " " + y + " " + z);
filler.block = Blocks.glass;
}
this.block = filler.block;
this.blockMeta = filler.metadata;
blockNBT = (filler.tag != null) ? (NBTTagCompound) filler.tag.copy() : null;
this.x = x;
this.y = y;
this.z = z;
}
public boolean deploy(World targetWorld, int offsetX, int offsetY, int offsetZ) {
try {
int newX = x + offsetX;

View file

@ -6,12 +6,10 @@ import net.minecraft.entity.Entity;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import cpw.mods.fml.common.FMLCommonHandler;
import cr0s.warpdrive.LocalProfiler;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.MetaBlock;
import cr0s.warpdrive.config.structures.Orb;
import cr0s.warpdrive.config.structures.Orb.OrbShell;
import cr0s.warpdrive.config.structures.OrbInstance;
import cr0s.warpdrive.data.JumpBlock;
/*
@ -51,12 +49,12 @@ public final class EntitySphereGen extends Entity {
private int radius;
private int gasColor;
private final int BLOCKS_PER_TICK = 5000;
private static final int BLOCKS_PER_TICK = 5000;
private final int STATE_SAVING = 0;
private final int STATE_SETUP = 1;
private final int STATE_DELETE = 2;
private final int STATE_STOP = 3;
private static final int STATE_SAVING = 0;
private static final int STATE_SETUP = 1;
private static final int STATE_DELETE = 2;
private static final int STATE_STOP = 3;
private int state = STATE_DELETE;
private int ticksDelay = 0;
@ -64,15 +62,14 @@ public final class EntitySphereGen extends Entity {
private int pregenSize = 0;
private ArrayList<JumpBlock> blocks;
private Orb orb;
private int[] thicknesses;
private OrbInstance orbInstance;
private boolean replace;
public EntitySphereGen(World world) {
super(world);
}
public EntitySphereGen(World world, int x, int y, int z, Orb orb, int[] thicknesses, int radius, boolean replace) {
public EntitySphereGen(World world, int x, int y, int z, OrbInstance orbInstance, boolean replace) {
super(world);
this.xCoord = x;
this.posX = x;
@ -80,14 +77,14 @@ public final class EntitySphereGen extends Entity {
this.posY = y;
this.zCoord = z;
this.posZ = z;
this.orbInstance = orbInstance;
this.gasColor = worldObj.rand.nextInt(12);
this.radius = radius;
this.radius = orbInstance.getTotalThickness();
this.state = STATE_SAVING;
this.pregenSize = (int) Math.ceil(Math.PI * 4.0F / 3.0F * Math.pow(radius + 1, 3));
blocks = new ArrayList<JumpBlock>(this.pregenSize);
this.ticksDelay = world.rand.nextInt(60);
this.orb = orb;
this.thicknesses = thicknesses;
this.replace = replace;
}
@ -152,54 +149,38 @@ public final class EntitySphereGen extends Entity {
}
private void tickScheduleBlocks() {
LocalProfiler.start("[EntitySphereGen] Saving blocks");
LocalProfiler.start("[EntitySphereGen] Saving blocks, radius " + radius);
// Radius from center of block
radius += 0.5D;
// square radius from center of block
double sqRadius = (radius + 0.5D) * (radius + 0.5D);
// sphere
int ceilRadius = (int) Math.ceil(radius);
int ceilRadius = radius + 1;
// 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);
for (int y = 0; y <= ceilRadius; y++) {
double y2 = (y + 0.5D) * (y + 0.5D);
double x2y2 = x2 + (y + 0.5D) * (y + 0.5D);
for (int z = 0; z <= ceilRadius; z++) {
double z2 = (z + 0.5D) * (z + 0.5D);
double dSq = Math.sqrt(x2 + y2 + z2); // Distance from current position to center
double sqRange = x2y2 + (z + 0.5D) * (z + 0.5D); // Square distance from current position to center
// Skip too far blocks
if (dSq > radius)
if (sqRange > sqRadius) {
continue;
int range = (int) Math.ceil(dSq);
}
// Add blocks to memory
OrbShell orbShell = orb.getShellForRadius(thicknesses, range);
MetaBlock metablock = orbShell.getRandomBlock(rand);
addBlock(new JumpBlock(metablock.block, metablock.metadata, xCoord + x, yCoord + y, zCoord + z));
metablock = orbShell.getRandomBlock(rand);
addBlock(new JumpBlock(metablock.block, metablock.metadata, xCoord - x, yCoord + y, zCoord + z));
metablock = orbShell.getRandomBlock(rand);
addBlock(new JumpBlock(metablock.block, metablock.metadata, xCoord + x, yCoord - y, zCoord + z));
metablock = orbShell.getRandomBlock(rand);
addBlock(new JumpBlock(metablock.block, metablock.metadata, xCoord + x, yCoord + y, zCoord - z));
metablock = orbShell.getRandomBlock(rand);
addBlock(new JumpBlock(metablock.block, metablock.metadata, xCoord - x, yCoord - y, zCoord + z));
metablock = orbShell.getRandomBlock(rand);
addBlock(new JumpBlock(metablock.block, metablock.metadata, xCoord + x, yCoord - y, zCoord - z));
metablock = orbShell.getRandomBlock(rand);
addBlock(new JumpBlock(metablock.block, metablock.metadata, xCoord - x, yCoord + y, zCoord - z));
metablock = orbShell.getRandomBlock(rand);
addBlock(new JumpBlock(metablock.block, metablock.metadata, xCoord - x, yCoord - y, zCoord - z));
OrbShell orbShell = orbInstance.getShellForSqRadius(sqRange);
// WarpDrive.logger.info("sqRange " + sqRange + " sqRadius " + sqRadius);
addBlock(new JumpBlock(orbShell.getRandomBlock(rand), xCoord + x, yCoord + y, zCoord + z));
addBlock(new JumpBlock(orbShell.getRandomBlock(rand), xCoord - x, yCoord + y, zCoord + z));
addBlock(new JumpBlock(orbShell.getRandomBlock(rand), xCoord + x, yCoord - y, zCoord + z));
addBlock(new JumpBlock(orbShell.getRandomBlock(rand), xCoord + x, yCoord + y, zCoord - z));
addBlock(new JumpBlock(orbShell.getRandomBlock(rand), xCoord - x, yCoord - y, zCoord + z));
addBlock(new JumpBlock(orbShell.getRandomBlock(rand), xCoord + x, yCoord - y, zCoord - z));
addBlock(new JumpBlock(orbShell.getRandomBlock(rand), xCoord - x, yCoord + y, zCoord - z));
addBlock(new JumpBlock(orbShell.getRandomBlock(rand), xCoord - x, yCoord - y, zCoord - z));
}
}
}
@ -231,6 +212,7 @@ public final class EntitySphereGen extends Entity {
@Override
protected void readEntityFromNBT(NBTTagCompound tag) {
// FIXME not implemented
}
@Override
@ -239,6 +221,7 @@ public final class EntitySphereGen extends Entity {
@Override
protected void writeEntityToNBT(NBTTagCompound tag) {
// FIXME not implemented
}
@Override

View file

@ -7,11 +7,11 @@ import net.minecraft.world.chunk.IChunkProvider;
import cpw.mods.fml.common.IWorldGenerator;
import cr0s.warpdrive.LocalProfiler;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.MetaBlock;
import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.config.structures.DeployableStructure;
import cr0s.warpdrive.config.structures.Orb;
import cr0s.warpdrive.config.filler.Filler;
import cr0s.warpdrive.config.structures.AbstractStructure;
import cr0s.warpdrive.config.structures.Orb.OrbShell;
import cr0s.warpdrive.config.structures.OrbInstance;
import cr0s.warpdrive.config.structures.StructureManager;
/**
@ -58,27 +58,24 @@ public class SpaceWorldGenerator implements IWorldGenerator {
int y = Y_LIMIT_SOFT_MIN + random.nextInt(Y_LIMIT_SOFT_MAX - Y_LIMIT_SOFT_MIN);
// Moon setup
if (random.nextInt(700) == 1) {
generateMoon(world, x, y, z, null);
// Simple asteroids
AbstractStructure moon = StructureManager.getStructure(world.rand, StructureManager.GROUP_MOONS, null);
moon.generate(world, world.rand, x, y, z);
// Simple asteroids
} else if (random.nextInt(150) == 1) {
generateRandomAsteroid(world, x, y, z);
// Random asteroid of block
AbstractStructure moon = StructureManager.getStructure(world.rand, StructureManager.GROUP_ASTEROIDS, null);
moon.generate(world, world.rand, x, y, z);
// Random asteroid of block
} else if (random.nextInt(500) == 1) {// Asteroid field
generateAsteroidField(world, x, y, z);
}
} catch (Exception e) {
e.printStackTrace();
} catch (Exception exception) {
exception.printStackTrace();
}
}
public static void generateMoon(World world, int x, int y, int z, final String moonName) {
DeployableStructure moon = StructureManager.getMoon(world.rand, moonName);
WarpDrive.logger.info("Generating moon (class " + moon + ") at " + x + " " + y + " " + z);
moon.generate(world, world.rand, x, y, z);
}
private static void generateSmallShip(World world, int x, int y, int z, int jitter) {
int x2 = x + (((world.rand.nextBoolean()) ? -1 : 1) * world.rand.nextInt(jitter));
int y2 = y + (((world.rand.nextBoolean()) ? -1 : 1) * world.rand.nextInt(jitter));
@ -170,7 +167,8 @@ public class SpaceWorldGenerator implements IWorldGenerator {
}
// Place an asteroid
generateRandomAsteroid(world, aX, aY, aZ);
AbstractStructure moon = StructureManager.getStructure(world.rand, StructureManager.GROUP_ASTEROIDS, null);
moon.generate(world, world.rand, aX, aY, aZ);
}
// Setting up small asteroids
@ -187,7 +185,8 @@ public class SpaceWorldGenerator implements IWorldGenerator {
// Placing
if (world.rand.nextInt(400) != 1) {
generateRandomAsteroid(world, aX, aY, aZ);
AbstractStructure moon = StructureManager.getStructure(world.rand, StructureManager.GROUP_ASTEROIDS, null);
moon.generate(world, world.rand, aX, aY, aZ);
} else {
if (world.rand.nextInt(20) != 1) {
generateSmallShip(world, aX, aY, aZ, 8);
@ -211,98 +210,24 @@ public class SpaceWorldGenerator implements IWorldGenerator {
// Placing
if (world.rand.nextBoolean()) {
generateGasCloudOfColor(world, aX, aY, aZ, 12, 15, null);
AbstractStructure gasCloud = StructureManager.getStructure(world.rand, StructureManager.GROUP_GASCLOUDS, null);
if (gasCloud != null) {
gasCloud.generate(world, world.rand, aX, aY, aZ);
}
}
}
LocalProfiler.stop();
}
/**
* Gas cloud generator
*
* @param x
* coordinate of center
* @param y
* coordinate of center
* @param z
* coordinate of center
* @param cloudSizeMax
* maximum gas cloud size (by number of balls it consists)
* @param centerRadiusMax
* maximum radius of central ball
*/
public static void generateGasCloudOfColor(World world, int x, int y, int z, int cloudSizeMax, int centerRadiusMax, final String type) {
int cloudSize = 1 + world.rand.nextInt(20);
if (cloudSizeMax != 0)
cloudSize = Math.min(cloudSizeMax, cloudSize);
int centerRadius = 1 + world.rand.nextInt(20);
if (centerRadiusMax != 0)
centerRadius = Math.min(centerRadiusMax, centerRadius);
final int CENTER_SHIFT = 2; // Offset from center of central ball
DeployableStructure cloud = StructureManager.getGasCloud(world.rand, type);
if (cloud == null) {
WarpDrive.logger.error("No gaz cloud defined, cancelling world generation");
return;
}
for (int i = 1; i <= cloudSize; i++) {
int radius = 2 + world.rand.nextInt(centerRadius);
int newX = x + (((world.rand.nextBoolean()) ? -1 : 1) * world.rand.nextInt(CENTER_SHIFT + centerRadius / 2));
int newY = y + (((world.rand.nextBoolean()) ? -1 : 1) * world.rand.nextInt(CENTER_SHIFT + centerRadius / 2));
int newZ = z + (((world.rand.nextBoolean()) ? -1 : 1) * world.rand.nextInt(CENTER_SHIFT + centerRadius / 2));
((Orb)cloud).generate(world, world.rand, newX, newY, newZ, radius);
}
}
/**
* Asteroid of block generator
*
* @param x
* coordinate of center
* @param y
* coordinate of center
* @param z
* coordinate of center
*/
public static void generateRandomAsteroid(World world, int x, int y, int z) {
DeployableStructure asteroid = StructureManager.getAsteroid(world.rand, null);
asteroid.generate(world, world.rand, x, y, z);
/*
int asteroidSize = 1 + world.rand.nextInt(6);
if (asteroidSizeMax != 0) {
asteroidSize = Math.min(asteroidSizeMax, asteroidSize);
}
int centerRadius = 1 + world.rand.nextInt(6);
if (centerRadiusMax != 0) {
centerRadius = Math.min(centerRadiusMax, centerRadius);
}
final int CENTER_SHIFT = 2; // Offset from center of central ball
// Asteroid's center
Block t = WarpDriveConfig.getDefaultSurfaceBlock(world.rand, true, false);
generateSphereDirect(world, x, y, z, centerRadius, true, ice, meta, false, t, 0);
// Asteroids knolls
for (int i = 1; i <= asteroidSize; i++) {
int radius = 1 + world.rand.nextInt(centerRadius);
int newX = x + (((world.rand.nextBoolean()) ? -1 : 1) * world.rand.nextInt(CENTER_SHIFT + centerRadius / 2));
int newY = y + (((world.rand.nextBoolean()) ? -1 : 1) * world.rand.nextInt(CENTER_SHIFT + centerRadius / 2));
int newZ = z + (((world.rand.nextBoolean()) ? -1 : 1) * world.rand.nextInt(CENTER_SHIFT + centerRadius / 2));
generateSphereDirect(world, newX, newY, newZ, radius, true, ice, meta, false, t, 0);
}
*/
}
/**
*
* @deprecated reference design for EntitySphereGenerator
**/
@Deprecated
public static void generateSphereDirect(
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
OrbInstance orbInstance, World world, int xCoord, int yCoord, int zCoord) {
double radiusC = orbInstance.getTotalThickness() + 0.5D; // Radius from center of block
double radiusSq = radiusC * radiusC; // Optimization to avoid sqrts...
// sphere
int ceilRadius = (int) Math.ceil(radiusC);
@ -324,16 +249,16 @@ public class SpaceWorldGenerator implements IWorldGenerator {
// Place blocks
// cheat by using axial symmetry so we don't create random numbers too frequently
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);
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);
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);
OrbShell orbShell = orbInstance.getShellForSqRadius(dSq);
Filler filler = orbShell.getRandomBlock(world.rand);
filler.setBlock(world, xCoord + x, yCoord + y, zCoord + z);
filler.setBlock(world, xCoord - x, yCoord + y, zCoord + z);
filler.setBlock(world, xCoord + x, yCoord - y, zCoord + z);
filler.setBlock(world, xCoord + x, yCoord + y, zCoord - z);
filler.setBlock(world, xCoord - x, yCoord - y, zCoord + z);
filler.setBlock(world, xCoord + x, yCoord - y, zCoord - z);
filler.setBlock(world, xCoord - x, yCoord + y, zCoord - z);
filler.setBlock(world, xCoord - x, yCoord - y, zCoord - z);
}
}
}

View file

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema elementFormDefault="qualified" targetNamespace="WarpDrive" xmlns="WarpDrive" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="forElement">
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element name="for" type="forElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="fillerSet" type="fillerSetElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="import" type="importElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="filler" type="fillerElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="structure" type="structureElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="metashell" type="metashellElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="shell" type="shellElement" maxOccurs="unbounded" minOccurs="0" />
</xs:choice>
<xs:attribute type="xs:string" name="variable" use="required" />
<xs:attribute type="xs:string" name="from" use="optional" />
<xs:attribute type="xs:string" name="to" use="optional" />
<xs:attribute type="xs:string" name="in" use="optional" />
<xs:attribute type="xs:string" name="mods" use="optional" />
</xs:complexType>
<xs:complexType name="fillerSetElement">
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element name="for" type="forElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="import" type="importElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="filler" type="fillerElement" maxOccurs="unbounded" minOccurs="0" />
</xs:choice>
<xs:attribute type="xs:string" name="group" use="required" />
<xs:attribute type="xs:string" name="name" use="required" />
<xs:attribute type="xs:string" name="weight" use="optional" />
<xs:attribute type="xs:string" name="ratio" use="optional" />
<xs:attribute type="xs:string" name="mods" use="optional" />
</xs:complexType>
<xs:complexType name="importElement">
<xs:attribute type="xs:string" name="group" use="required" />
<xs:attribute type="xs:string" name="name" use="optional" />
<xs:attribute type="xs:string" name="mods" use="optional" />
</xs:complexType>
<xs:complexType name="fillerElement">
<xs:attribute type="xs:string" name="block" use="required" />
<xs:attribute type="xs:string" name="metadata" use="optional" />
<xs:attribute type="xs:string" name="weight" use="optional" />
<xs:attribute type="xs:string" name="ratio" use="optional" />
<xs:attribute type="xs:string" name="mods" use="optional" />
</xs:complexType>
<xs:complexType name="structureElement">
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element name="for" type="forElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="import" type="importElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="schematic" type="schematicElement" maxOccurs="1" minOccurs="0" />
<xs:element name="metashell" type="metashellElement" maxOccurs="1" minOccurs="0" />
<xs:element name="shell" type="shellElement" maxOccurs="unbounded" minOccurs="0" />
</xs:choice>
<xs:attribute type="xs:string" name="group" use="required" />
<xs:attribute type="xs:string" name="name" use="required" />
<xs:attribute type="xs:string" name="weight" use="optional" />
<xs:attribute type="xs:string" name="ratio" use="optional" />
<xs:attribute type="xs:string" name="mods" use="optional" />
</xs:complexType>
<xs:complexType name="schematicElement">
<xs:attribute type="xs:string" name="group" use="required" />
<xs:attribute type="xs:string" name="name" use="optional" />
<xs:attribute type="xs:string" name="mods" use="optional" />
</xs:complexType>
<xs:complexType name="metashellElement">
<xs:attribute type="xs:string" name="block" use="optional" />
<xs:attribute type="xs:string" name="metadata" use="optional" />
<xs:attribute type="xs:string" name="minCount" use="required" />
<xs:attribute type="xs:string" name="maxCount" use="required" />
<xs:attribute type="xs:string" name="minRadius" use="required" />
<xs:attribute type="xs:string" name="relativeRadius" use="required" />
<xs:attribute type="xs:string" name="mods" use="optional" />
</xs:complexType>
<xs:complexType name="shellElement">
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element name="for" type="forElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="import" type="importElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="filler" type="fillerElement" maxOccurs="unbounded" minOccurs="0" />
</xs:choice>
<xs:attribute type="xs:string" name="name" use="required" />
<xs:attribute type="xs:string" name="minThickness" use="required" />
<xs:attribute type="xs:string" name="maxThickness" use="required" />
<xs:attribute type="xs:string" name="mods" use="optional" />
</xs:complexType>
<xs:element name="worldGeneration">
<xs:complexType>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element name="for" type="forElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="fillerSet" type="fillerSetElement" maxOccurs="unbounded" minOccurs="0" />
<xs:element name="structure" type="structureElement" maxOccurs="unbounded" minOccurs="0" />
</xs:choice>
<xs:attribute type="xs:string" name="version" use="required" />
<xs:attribute type="xs:string" name="mods" use="optional" />
</xs:complexType>
</xs:element>
</xs:schema>

View file

@ -1,74 +1,285 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE warpdriveWorldGeneration>
<warpdriveWorldGeneration version="1">
<worldGeneration version="2" xmlns="WarpDrive" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="WarpDrive warpDrive.xsd">
<FillerSet group="stone_ores" name="default_stone_ores">
<!-- all possible overworld ores, mostly for reference purpose -->
<fillerSet group="overworld_allOres" name="stone">
<import group="overworld_commonOres" name="stone" />
<import group="overworld_uncommonOres" name="stone" />
<import group="overworld_rareOres" name="stone" />
</fillerSet>
<!-- common overworld ores with various base blocks -->
<fillerSet group="overworld_common" name="stone" weight="20">
<import group="overworld_commonOres" name="stone" />
<filler block="minecraft:stone" weight="1" />
</fillerSet>
<fillerSet group="overworld_common" name="corrupted" weight="5">
<import group="overworld_commonOres" name="stone" />
<filler block="minecraft:stone" weight="5" />
<filler block="minecraft:cobblestone" weight="1" />
</fillerSet>
<fillerSet group="overworld_common" name="cobblestone" weight="1">
<import group="overworld_commonOres" name="stone" />
<filler block="minecraft:cobblestone" weight="1" />
</fillerSet>
<fillerSet group="overworld_common" name="sandNclay" weight="2">
<import group="overworld_commonOres" name="stone" />
<filler block="minecraft:sandstone" weight="1" />
<filler block="minecraft:clay" weight="1" />
</fillerSet>
<fillerSet group="overworld_commonOres" name="stone">
<import group="overworld_commonOres" name="allButVanilla" />
<filler block="minecraft:coal_ore" ratio=".08" />
<filler block="minecraft:iron_ore" ratio=".05" />
<filler block="minecraft:redstone_ore" ratio=".05" />
<filler block="minecraft:gold_ore" ratio=".008" />
<filler block="minecraft:lapis_ore" ratio=".005" />
<filler block="minecraft:emerald_ore" ratio=".005" />
<filler block="IC2:blockOreTin" ratio=".05" mods="IC2" />
<filler block="IC2:blockOreCopper" ratio=".06" mods="IC2" />
<filler block="IC2:blockOreLead" ratio=".06" mods="IC2" />
<filler block="IC2:blockOreUran" ratio=".001" mods="IC2" />
<filler block="ImmersiveEngineering:ore" metadata="0" ratio=".001" mods="ImmersiveEngineering" /><!-- Copper -->
<filler block="ImmersiveEngineering:ore" metadata="1" ratio=".001" mods="ImmersiveEngineering" /><!-- Bauxite -->
<filler block="ImmersiveEngineering:ore" metadata="2" ratio=".001" mods="ImmersiveEngineering" /><!-- Lead -->
<filler block="ImmersiveEngineering:ore" metadata="3" ratio=".001" mods="ImmersiveEngineering" /><!-- Silver -->
<filler block="ImmersiveEngineering:ore" metadata="4" ratio=".001" mods="ImmersiveEngineering" /><!-- Nickel -->
<filler block="arsmagica2:vinteumOre" metadata="0" ratio=".001" mods="arsmagica2" /><!-- Vinteum -->
<filler block="arsmagica2:vinteumOre" metadata="1" ratio=".001" mods="arsmagica2" /><!-- Chimerite -->
<filler block="arsmagica2:vinteumOre" metadata="2" ratio=".001" mods="arsmagica2" /><!-- Blue topaz -->
<filler block="arsmagica2:vinteumOre" metadata="3" ratio=".001" mods="arsmagica2" /><!-- Moonstone -->
<filler block="arsmagica2:vinteumOre" metadata="4" ratio=".001" mods="arsmagica2" /><!-- Sunstone -->
<filler block="minecraft:diamond_ore" ratio=".004" />
<filler block="warpdrive:iridiumBlock" ratio=".0001" mods="!netherores" />
<filler block="icbm:sulfur_ore" ratio=".001" /><!-- to be confirmed -->
<filler block="ae2:quartz" ratio=".0013" /><!-- to be confirmed -->
<filler block="minecraft:water" ratio=".001" />
<filler block="minecraft:bedrock" ratio=".001" />
</FillerSet>
<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" 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" name="default_rareOres">
</fillerSet>
<fillerSet group="overworld_commonOres" name="allButVanilla">
<filler block="IC2:blockOreTin" ratio=".05" mods="IC2,!ImmersiveEngineering" />
<filler block="IC2:blockOreCopper" ratio=".06" mods="IC2,!ImmersiveEngineering" />
<filler block="IC2:blockOreLead" ratio=".06" mods="IC2,!ImmersiveEngineering" />
<filler block="ImmersiveEngineering:ore" metadata="0" ratio=".05" mods="ImmersiveEngineering" /><!-- Copper -->
<filler block="ImmersiveEngineering:ore" metadata="1" ratio=".06" mods="ImmersiveEngineering" /><!-- Bauxite -->
<filler block="ImmersiveEngineering:ore" metadata="2" ratio=".06" mods="ImmersiveEngineering" /><!-- Lead -->
<filler block="arsmagica2:vinteumOre" metadata="0" ratio=".001" mods="arsmagica2" /><!-- Vinteum -->
<filler block="icbm:sulfur_ore" ratio=".001" /><!-- to be confirmed -->
</fillerSet>
<!-- uncommon overworld ores with various base blocks -->
<fillerSet group="overworld_uncommon" name="stone" weight="10">
<import group="overworld_uncommonOres" name="stone" />
<filler block="minecraft:stone" weight="1" />
</fillerSet>
<fillerSet group="overworld_uncommon" name="corrupted" weight="5">
<import group="overworld_uncommonOres" name="stone" />
<filler block="minecraft:stone" weight="5" />
<filler block="minecraft:cobblestone" weight="1" />
</fillerSet>
<fillerSet group="overworld_uncommon" name="cobblestone" weight="1">
<import group="overworld_uncommonOres" name="stone" />
<filler block="minecraft:cobblestone" weight="1" />
</fillerSet>
<fillerSet group="overworld_uncommon" name="sandNclay" weight="2">
<import group="overworld_uncommonOres" name="stone" />
<filler block="minecraft:sandstone" weight="1" />
<filler block="minecraft:clay" weight="1" />
</fillerSet>
<fillerSet group="overworld_uncommonOres" name="stone">
<import group="overworld_uncommonOres" name="allButVanilla" />
<filler block="minecraft:redstone_ore" ratio=".01" />
<filler block="minecraft:gold_ore" ratio=".008" />
<filler block="minecraft:diamond_ore" ratio=".001" />
<filler block="minecraft:lapis_ore" ratio=".005" />
<filler block="minecraft:emerald_ore" ratio=".005" />
<filler block="warpdrive:iridiumBlock" ratio=".0001" />
</FillerSet>
<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" 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" name="default_nether">
<filler block="minecraft:netherrack" weight="300" />
<filler block="minecraft:quartz_ore" weight="20" />
<filler block="minecraft:glowstone" weight="40" />
</FillerSet>
</warpdriveWorldGeneration>
</fillerSet>
<fillerSet group="overworld_uncommonOres" name="allButVanilla">
<filler block="IC2:blockOreUran" ratio=".005" mods="IC2,!netherores" />
<filler block="ImmersiveEngineering:ore" metadata="3" ratio=".03" mods="ImmersiveEngineering" /><!-- Silver -->
<filler block="ImmersiveEngineering:ore" metadata="4" ratio=".02" mods="ImmersiveEngineering" /><!-- Nickel -->
<filler block="arsmagica2:vinteumOre" metadata="1" ratio=".01" mods="arsmagica2" /><!-- Chimerite -->
</fillerSet>
<!-- rare overworld ores with various base blocks -->
<fillerSet group="overworld_rare" name="stone" weight="10">
<import group="overworld_rareOres" name="stone" />
<filler block="minecraft:stone" weight="100" />
<filler block="minecraft:iron_ore" weight="5" />
<filler block="minecraft:lava" weight="1" />
</fillerSet>
<fillerSet group="overworld_rare" name="obsidian" weight="2">
<import group="overworld_rareOres" name="stone" />
<filler block="minecraft:obsidian" weight="100" />
<filler block="minecraft:diamond_ore" weight="10" />
<filler block="minecraft:bedrock" weight="1" />
</fillerSet>
<fillerSet group="overworld_rareOres" name="stone">
<import group="overworld_rareOres" name="allButVanilla" />
<filler block="minecraft:gold_ore" ratio=".004" />
<filler block="minecraft:diamond_ore" ratio=".004" />
<filler block="minecraft:emerald_ore" ratio=".001" />
</fillerSet>
<fillerSet group="overworld_rareOres" name="allButVanilla">
<filler block="IC2:blockOreUran" ratio=".03" mods="IC2,!netherores" />
<filler block="arsmagica2:vinteumOre" metadata="2" ratio=".01" mods="arsmagica2" /><!-- Blue topaz -->
</fillerSet>
<!-- nether ores with simple base block -->
<fillerSet group="nether" name="stone" weight="10">
<import group="nether_ores" name="netherrack" />
<filler block="minecraft:netherrack" weight="100" />
<filler block="minecraft:lava" weight="5" />
</fillerSet>
<fillerSet group="nether_ores" name="netherrack">
<filler block="minecraft:quartz_ore" ratio="0.1" />
<filler block="minecraft:glowstone" ratio="0.01" />
<filler block="minecraft:lava" ratio="0.02" />
<filler block="arsmagica2:vinteumOre" metadata="4" ratio=".001" mods="arsmagica2" /><!-- Sunstone -->
<filler block="minecraft:bedrock" ratio=".001" />
</fillerSet>
<!-- end ores with simple base block -->
<fillerSet group="end" name="end" weight="10">
<import group="end_ores" name="endstone" />
<filler block="minecraft:netherrack" weight="100" />
<filler block="minecraft:lava" weight="5" />
</fillerSet>
<fillerSet group="end_ores" name="endstone">
<filler block="arsmagica2:vinteumOre" metadata="3" ratio=".001" mods="arsmagica2" /><!-- Moonstone -->
<filler block="ae2:quartz" ratio=".0013" mods="appliedenergistics2" />
<filler block="WarpDrive:blockIridium" ratio=".0001" mods="!netherores" />
</fillerSet>
<!-- assorted overworld surface blocks -->
<fillerSet group="overworld_surface" name="stone" weight="75">
<filler block="minecraft:stone" weight="100" />
</fillerSet>
<fillerSet group="overworld_surface" name="cobblestone" weight="45">
<filler block="minecraft:stone" weight="100" />
<filler block="minecraft:cobblestone" weight="20" />
</fillerSet>
<fillerSet group="overworld_surface" name="dirt" weight="20">
<filler block="minecraft:dirt" weight="100" />
</fillerSet>
<fillerSet group="overworld_surface" name="ice" weight="30">
<filler block="minecraft:packed_ice" weight="100" />
<filler block="minecraft:ice" weight="20" />
</fillerSet>
<for variable="metadata" from="0" to="15">
<fillerSet group="overworld_surface" name="stainedClay_%metadata%" weight="5">
<filler block="minecraft:stained_hardened_clay" metadata="%metadata%" weight="100" />
</fillerSet>
</for>
<fillerSet group="overworld_surface" name="hardenedClay" weight="5">
<filler block="minecraft:hardened_clay" weight="100" />
</fillerSet>
<fillerSet group="overworld_surface" name="sandy" weight="10"><!-- close color to endstone -->
<filler block="minecraft:sandstone" weight="100" />
</fillerSet>
<!-- assorted nether surface blocks -->
<fillerSet group="nether_surface" name="netherrack" weight="50">
<filler block="minecraft:netherrack" weight="100" />
</fillerSet>
<fillerSet group="nether_surface" name="quartz" weight="50">
<filler block="minecraft:netherrack" weight="100" />
<filler block="minecraft:quartz_ore" weight="2" />
</fillerSet>
<for variable="metadata" in="1,6,14">
<fillerSet group="nether_surface" name="stainedClay_%metadata%" weight="15">
<filler block="minecraft:stained_hardened_clay" metadata="%metadata%" weight="5" />
</fillerSet>
</for>
<fillerSet group="nether_surface" name="soulsand" weight="20">
<filler block="minecraft:soul_sand" weight="100" />
</fillerSet>
<!-- assorted end surface blocks -->
<fillerSet group="end_surface" name="endstone" weight="50">
<filler block="minecraft:end_stone" weight="100" />
</fillerSet>
<fillerSet group="end_surface" name="obsiend" weight="50">
<filler block="minecraft:end_stone" weight="100" />
<filler block="minecraft:obsidian" weight="15" />
</fillerSet>
<for variable="metadata" in="0,4">
<fillerSet group="end_surface" name="stainedClay_%metadata%" weight="15">
<filler block="minecraft:stained_hardened_clay" metadata="%metadata%" weight="100" />
</fillerSet>
</for>
<fillerSet group="end_surface" name="clay" weight="15">
<filler block="minecraft:clay" weight="100" />
</fillerSet>
<fillerSet group="end_surface" name="sandy" weight="15">
<filler block="minecraft:sandstone" weight="100" />
</fillerSet>
<!-- WarpDrive gases -->
<for variable="gasMetadata" in="0,1,2,3,4,5,6,7,8,9,10,11">
<fillerSet group="gas" name="wd_%gasMetadata%" weight="1">
<filler block="WarpDrive:blockGas" metadata="%gasMetadata%" weight="100" />
</fillerSet>
</for>
<!-- flow variation for moons -->
<fillerSet group="moon.flow" name="lava" weight="5">
<filler block="minecraft:lava" weight="100" />
</fillerSet>
<fillerSet group="moon.flow" name="sand" weight="1">
<filler block="minecraft:sand" weight="100" />
</fillerSet>
<fillerSet group="moon.flow" name="gravel" weight="1">
<filler block="minecraft:gravel" weight="100" />
</fillerSet>
<fillerSet group="moon.flow" name="ice" weight="3">
<filler block="minecraft:ice" weight="100" />
</fillerSet>
<fillerSet group="moon.flow" name="clay" weight="5">
<filler block="minecraft:clay" weight="100" />
</fillerSet>
<fillerSet group="moon.flow" name="water" weight="5">
<filler block="minecraft:water" weight="100" />
</fillerSet>
<fillerSet group="moon.flow" name="empty" ratio="0.35">
<!-- empty fillerSet gives a random chance for the related shell to not exist at all -->
</fillerSet>
<!-- core variation for moons -->
<fillerSet group="moon.core" name="lava" weight="6">
<filler block="minecraft:lava" weight="100" />
<filler block="arsmagica2:vinteumOre" metadata="4" ratio=".001" mods="arsmagica2" /><!-- Sunstone -->
</fillerSet>
<fillerSet group="moon.core" name="stone" weight="5">
<import group="overworld_rare" name="stone" />
</fillerSet>
<fillerSet group="moon.core" name="obsidian" weight="1">
<import group="overworld_rare" name="obsidian" />
</fillerSet>
<fillerSet group="moon.core" name="water" weight="2">
<filler block="minecraft:water" weight="100" />
<filler block="minecraft:ice" ratio="0.05" />
</fillerSet>
<fillerSet group="moon.core" name="ice" weight="1">
<filler block="minecraft:packed_ice" weight="100" />
<filler block="minecraft:lapis_block" ratio="0.02" />
</fillerSet>
<fillerSet group="moon.core" name="diaquartz" weight="1">
<filler block="minecraft:quartz_block" metadata="0" weight="100" />
<filler block="minecraft:quartz_block" metadata="1" weight="100" />
<filler block="minecraft:diamond_block" ratio="0.01" />
</fillerSet>
<fillerSet group="moon.core" name="iriquartz" weight="1">
<filler block="minecraft:quartz_block" metadata="0" weight="100" />
<filler block="WarpDrive:blockIridium" ratio="0.001" />
</fillerSet>
<fillerSet group="moon.core" name="iroquartz" weight="1">
<filler block="minecraft:quartz_block" metadata="2" weight="33" />
<filler block="minecraft:quartz_block" metadata="3" weight="33" />
<filler block="minecraft:quartz_block" metadata="4" weight="33" />
<filler block="minecraft:iron_block" ratio="0.01" />
</fillerSet>
<!-- TODO: add GT granite cores -->
<!-- TODO: add TE/EIO block of sort -->
</worldGeneration>

View file

@ -1,14 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE warpdriveWorldGeneration>
<warpdriveWorldGeneration version="1" mods="netherores">
<worldGeneration version="2"
xmlns="WarpDrive"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="WarpDrive warpDrive.xsd"
mods="netherores">
<FillerSet group="nether" name="netherores_nether">
<!-- reference ratios
Coal( 8, 16, 2, 5),
Diamond( 4, 3, 2, 5, true),
Gold( 8, 6, 2, 4),
Iron( 8, 8, 2, 4),
Lapis( 6, 6, 2, 24, true),
Redstone( 6, 8, 2, 21, "dust", true),
Copper( 8, 8, 2, 4),
Tin( 8, 8, 2, 4),
Emerald( 3, 2, 2, 5, true),
Silver( 6, 4, 2, 4),
Lead( 6, 6, 2, 4),
Uranium( 3, 2, 2, 4, "crushed"),
Nikolite( 8, 4, 2, 21, "dust", true),
Ruby( 6, 3, 2, 5, true),
Peridot( 6, 3, 2, 5, true),
Sapphire( 6, 3, 2, 5, true),
Platinum( 1, 3, 2, 4),
Nickel( 4, 6, 2, 4),
Steel( 3, 4, 2, 4),
Iridium( 1, 2, 2, 4, "drop"),
Osmium( 8, 7, 2, 4),
Sulfur( 12, 12, 2, 24, false),
Titanium( 3, 2, 2, 4),
Mithril( 6, 6, 2, 4),
Adamantium( 5, 4, 2, 4),
Rutile( 3, 4, 2, 4),
Tungsten( 8, 8, 2, 4),
Amber( 5, 6, 2, 5, true),
Tennantite( 8, 8, 2, 4),
Salt( 5, 5, 2, 12, "food", true),
Saltpeter( 6, 4, 2, 10, false),
Magnesium( 4, 5, 2, 8, "crushed");
-->
<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" />
<filler block="netherores:ore" metadata="0" weight="15" />
<filler block="netherores:ore" metadata="0" weight="5" />
</FillerSet>
</fillerSet>
</warpdriveWorldGeneration>
</worldGeneration>

View file

@ -1,29 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE warpdriveWorldGeneration>
<warpdriveWorldGeneration version="1" mods="UndergroundBiomes">
<worldGeneration version="2"
xmlns="WarpDrive"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="WarpDrive warpDrive.xsd"
mods="UndergroundBiomes">
<for variable="type" in="igneous,metamorphic,sedimentary">
<for variable="metadata" from="0" to="7">
<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" />
<!-- common overworld ores with various base blocks -->
<fillerSet group="overworld_common" name="%type%@%metadata%.normal" weight="15">
<import group="undergroundBiomes_commonOres" name="%type%@%metadata%" />
<filler block="UndergroundBiomes:%type%Stone" metadata="%metadata%" weight="100" />
</fillerSet>
<fillerSet group="undergroundBiomes_commonOres" name="%type%@%metadata%">
<import group="overworld_commonOres" name="allButVanilla" />
<filler block="UndergroundBiomes:%type%_oreCoal" metadata="%metadata%" ratio=".08" />
<filler block="UndergroundBiomes:%type%_oreIron" metadata="%metadata%" ratio=".05" />
<filler block="UndergroundBiomes:%type%_oreRedstone" metadata="%metadata%" ratio=".02" />
</fillerSet>
<!-- uncommon overworld ores with various base blocks -->
<fillerSet group="overworld_uncommon" name="%type%@%metadata%.normal" weight="20">
<import group="undergroundBiomes_uncommonOres" name="%type%@%metadata%" />
<filler block="UndergroundBiomes:%type%Stone" metadata="%metadata%" weight="100" />
</fillerSet>
<fillerSet group="undergroundBiomes_uncommonOres" name="%type%@%metadata%">
<import group="overworld_uncommonOres" name="allButVanilla" />
<filler block="UndergroundBiomes:%type%_oreRedstone" metadata="%metadata%" ratio=".01" />
<filler block="UndergroundBiomes:%type%_oreGold" metadata="%metadata%" ratio=".008" />
<filler block="UndergroundBiomes:%type%_oreLapis" metadata="%metadata%" ratio=".005" />
</fillerSet>
<!-- rare overworld ores with various base blocks -->
<fillerSet group="overworld_rare" name="%type%@%metadata%.normal" weight="20">
<import group="undergroundBiomes_rareOres" name="%type%@%metadata%" />
<filler block="UndergroundBiomes:%type%Stone" metadata="%metadata%" weight="100" />
</fillerSet>
<fillerSet group="undergroundBiomes_rareOres" name="%type%@%metadata%">
<import group="overworld_rareOres" name="allButVanilla" />
<filler block="UndergroundBiomes:%type%_oreGold" metadata="%metadata%" ratio=".004" />
<filler block="UndergroundBiomes:%type%_oreDiamond" metadata="%metadata%" ratio=".004" />
<filler block="UndergroundBiomes:%type%_oreEmerald" metadata="%metadata%" ratio=".001" />
<filler block="UndergroundBiomes:%type%_oreGold" metadata="%metadata%" ratio=".001" />
<filler block="UndergroundBiomes:%type%_oreIron" metadata="%metadata%" ratio=".001" />
<filler block="UndergroundBiomes:%type%_oreLapis" metadata="%metadata%" ratio=".001" />
<filler block="UndergroundBiomes:%type%_oreRedstone" metadata="%metadata%" ratio=".001" />
</FillerSet>
<FillerSet group="overworld" name="%type%_ores@%metadata%.normal" fillerSets="%type%_ores@%metadata%">
<filler block="UndergroundBiomes:%type%Stone" metadata="%metadata%" weight="10" />
</FillerSet>
<FillerSet group="overworld" name="%type%_ores@%metadata%.corrupted" fillerSets="%type%_ores@%metadata%">
<filler block="UndergroundBiomes:%type%Cobblestone" metadata="%metadata%" weight="10" />
</FillerSet>
</fillerSet>
<!-- assorted overworld surface blocks -->
<fillerSet group="overworld_surface" name="%type%@%metadata%" weight="5">
<filler block="UndergroundBiomes:%type%Stone" weight="100" />
</fillerSet>
</for>
</for>
</warpdriveWorldGeneration>
<!-- corrupted versions (no sedimentary cobblestone) -->
<for variable="type" in="igneous,metamorphic">
<for variable="metadata" from="0" to="7">
<!-- common overworld ores with various base blocks -->
<fillerSet group="overworld_common" name="%type%@%metadata%.corrupted" weight="5">
<import group="undergroundBiomes_commonOres" name="%type%@%metadata%" />
<filler block="UndergroundBiomes:%type%Cobblestone" metadata="%metadata%" weight="100" />
</fillerSet>
<!-- uncommon overworld ores with various base blocks -->
<fillerSet group="overworld_uncommon" name="%type%@%metadata%.corrupted" weight="5">
<import group="undergroundBiomes_uncommonOres" name="%type%@%metadata%" />
<filler block="UndergroundBiomes:%type%Cobblestone" metadata="%metadata%" weight="100" />
</fillerSet>
<!-- rare overworld ores with various base blocks -->
<fillerSet group="overworld_rare" name="%type%@%metadata%.corrupted" weight="5">
<import group="undergroundBiomes_rareOres" name="%type%@%metadata%" />
<filler block="minecraft:obsidian" weight="100" />
<filler block="UndergroundBiomes:%type%_oreDiamond" metadata="%metadata%" weight="10" />
<filler block="minecraft:bedrock" weight="1" />
</fillerSet>
<!-- assorted overworld surface blocks -->
<fillerSet group="overworld_surface" name="%type%@%metadata%.corrupted" weight="2">
<filler block="UndergroundBiomes:%type%Cobblestone" weight="100" />
</fillerSet>
</for>
</for>
</worldGeneration>

View file

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE warpdriveWorldGeneration>
<warpdriveWorldGeneration version="1">
<worldGeneration version="2"
xmlns="WarpDrive"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="WarpDrive warpDrive.xsd">
<structure group="star" name="red_dwarf">
<structure group="star" name="red_dwarf" ratio="0.2">
<shell name="core" minThickness="40" maxThickness="50"><!-- legacy radius was 42 -->
<filler weight="1" block="minecraft:redstone_block" />
</shell>
@ -17,19 +19,19 @@
</shell>
</structure>
<structure group="star" name="orange_dwarf">
<structure group="star" name="orange_dwarf" weight="1">
<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 -->
<shell name="mantle" 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 -->
<shell name="crust1" 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">
<shell name="crust2" 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 -->
@ -37,16 +39,16 @@
</shell>
</structure>
<structure group="star" name="yellow_giant">
<structure group="star" name="yellow_giant" weight="1">
<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 -->
<shell name="mantle" 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 -->
<shell name="crust" 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 -->
@ -60,15 +62,15 @@
</shell>
</structure>
<structure group="star" name="yellow_supergiant">
<structure group="star" name="yellow_supergiant" ratio="0.2">
<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 -->
<shell name="mantle" 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 -->
<shell name="crust" 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 -->
@ -83,76 +85,281 @@
</structure>
<!--
<structure group="moon" name="test" weight="100">
<shell name="core" minThickness="1" maxThickness="1">
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="mantle" minThickness="1" maxThickness="1">
<filler block="minecraft:glass" ratio=".001" />
</shell>
<shell name="crust" minThickness="1" maxThickness="1">
<filler block="minecraft:stained_glass" metadata="5" ratio=".001" />
</shell>
<shell name="surface" minThickness="1" maxThickness="1">
<filler block="minecraft:stained_glass" metadata="15" />
</shell>
</structure>
-->
<structure group="moon" name="theMoon">
<shell name="core" minThickness="1" maxThickness="5" fillerSets="rareOres">
<filler weight="100" block="minecraft:iron_ore" />
</shell>
<shell name="mantle" minThickness="6" maxThickness="20" fillerSets="commonOres,uncommonOres">
<filler weight="10" block="minecraft:stone" />
<filler weight="3" block="minecraft:clay" />
</shell>
<shell name="surface" minThickness="10" maxThickness="20" fillerSets="overworld,commonOres">
<filler weight="3" block="minecraft:clay" />
</shell>
</structure>
<structure group="moon" name="theCorruptedMoon">
<shell name="core" minThickness="1" maxThickness="5" fillerSets="rareOres">
<filler weight="100" block="minecraft:iron_ore" />
</shell>
<shell name="mantle" minThickness="6" maxThickness="20" fillerSets="commonOres,uncommonOres">
<filler weight="10" block="minecraft:stone" />
<filler weight="3" block="minecraft:clay" />
<filler ratio=".2" block="minecraft:air" />
<filler ratio=".4" block="minecraft:cobblestone" />
</shell>
<shell name="surface" minThickness="10" maxThickness="20" fillerSets="overworld,commonOres">
<filler weight="3" block="minecraft:clay" />
<filler ratio=".05" block="minecraft:brick_block" />
<filler ratio=".5" block="minecraft:air" />
</shell>
</structure>
<structure group="moon" name="nether_moon">
<shell name="substance" fillerSets="commonOres" minThickness="10" maxThickness="30">
<filler block="minecraft:netherrack" weight="1" />
<filler block="minecraft:lava" ratio=".001" />
<structure group="moon" name="overworld.base" weight="100">
<shell name="core" minThickness="4" maxThickness="15">
<import group="moon.core" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
</structure>
<structure group="moon" name="end_moon">
<shell name="substance" minThickness="10" maxThickness="30">
<filler block="minecraft:end_stone" weight="1" />
<shell name="mantle" minThickness="3" maxThickness="15">
<import group="overworld_uncommon" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="flow" minThickness="0" maxThickness="2">
<import group="moon.flow" />
</shell>
<shell name="crust" minThickness="2" maxThickness="10">
<import group="overworld_common" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="surface" minThickness="1" maxThickness="3">
<import group="overworld_surface" />
</shell>
</structure>
<structure group="moon" name="overworld.rare" weight="20">
<shell name="core" minThickness="1" maxThickness="10">
<import group="moon.core" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="mantle" minThickness="3" maxThickness="15">
<import group="overworld_rare" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="flow" minThickness="1" maxThickness="3">
<import group="moon.flow" />
</shell>
<shell name="crust" minThickness="2" maxThickness="10">
<import group="overworld_common" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="surface" minThickness="1" maxThickness="3">
<import group="overworld_surface" />
</shell>
</structure>
<structure group="moon" name="overworld.empty" weight="20">
<shell name="core" minThickness="1" maxThickness="1">
<filler block="minecraft:bedrock" weight="100" />
</shell>
<shell name="empty" minThickness="6" maxThickness="29">
<import group="gas" />
</shell>
<shell name="innerCrust" minThickness="1" maxThickness="1">
<filler block="minecraft:obsidian" weight="100" />
<filler block="minecraft:bedrock" ratio=".001" />
<filler block="minecraft:glowstone" ratio=".001" />
</shell>
<shell name="mantle" minThickness="0" maxThickness="2">
<filler block="minecraft:obsidian" weight="100" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="crust" minThickness="1" maxThickness="5">
<import group="overworld_common" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="surface" minThickness="2" maxThickness="3">
<import group="overworld_surface" />
</shell>
</structure>
<structure group="moon" name="overworld.ship" weight="10">
<schematic group="smallship" />
<shell name="core" minThickness="5" maxThickness="16">
<import group="gas" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="mantle" minThickness="3" maxThickness="17">
<import group="overworld_uncommon" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="flow" minThickness="0" maxThickness="2">
<filler block="minecraft:obsidian" weight="100" />
</shell>
<shell name="crust" minThickness="2" maxThickness="10">
<import group="overworld_common" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="surface" minThickness="1" maxThickness="3">
<import group="overworld_surface" />
</shell>
</structure>
<structure group="moon" name="overworld.corrupted" weight="20">
<shell name="core" minThickness="5" maxThickness="16">
<import group="overworld_rare" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="mantle" minThickness="6" maxThickness="20">
<import group="overworld_uncommon" />
<filler block="minecraft:bedrock" ratio=".001" />
<filler block="minecraft:gravel" ratio=".1" />
<filler block="minecraft:lava" ratio=".05" />
</shell>
<shell name="crust" minThickness="10" maxThickness="20">
<import group="overworld_common" />
<filler block="minecraft:bedrock" ratio=".001" />
<filler block="minecraft:sand" ratio=".1" />
<filler block="minecraft:air" ratio=".2" />
</shell>
<shell name="surface" minThickness="2" maxThickness="4">
<import group="overworld_surface" />
<filler block="minecraft:air" ratio=".35" />
</shell>
</structure>
<structure group="moon" name="nether" ratio="0.1">
<shell name="core" minThickness="1" maxThickness="5">
<filler block="minecraft:air" weight="1" />
<filler block="minecraft:bedrock" ratio=".01" />
</shell>
<shell name="coreShell" minThickness="1" maxThickness="1">
<filler block="minecraft:obsidian" weight="100" />
</shell>
<shell name="mantle" minThickness="6" maxThickness="20">
<import group="nether" />
<filler block="minecraft:bedrock" ratio=".001" />
<filler block="minecraft:glass" ratio=".2" />
</shell>
<shell name="crust" minThickness="10" maxThickness="20">
<import group="nether" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="surface" minThickness="2" maxThickness="4">
<import group="nether_surface" />
</shell>
</structure>
<structure group="moon" name="nether.corrupted" ratio="0.1">
<shell name="core" minThickness="1" maxThickness="5">
<filler block="minecraft:air" weight="1" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="coreShell" minThickness="1" maxThickness="1">
<filler block="minecraft:obsidian" weight="100" />
</shell>
<shell name="mantle" minThickness="6" maxThickness="12">
<import group="nether" />
<filler block="minecraft:bedrock" ratio=".001" />
<filler block="minecraft:glass" ratio=".1" />
</shell>
<shell name="crust" minThickness="8" maxThickness="16">
<import group="nether" />
<filler block="minecraft:bedrock" ratio=".001" />
<filler block="minecraft:air" ratio=".2" />
</shell>
<shell name="surface" minThickness="2" maxThickness="4">
<import group="nether_surface" />
<filler block="minecraft:air" ratio=".25" />
</shell>
</structure>
<structure group="moon" name="enderack" ratio="0.03">
<shell name="core" minThickness="5" maxThickness="15">
<import group="end" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="mantle" minThickness="10" maxThickness="25">
<import group="end" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="surface" minThickness="2" maxThickness="3">
<import group="end_surface" />
</shell>
</structure>
<structure group="moon" name="end" ratio="0.05">
<shell name="core" minThickness="5" maxThickness="15">
<import group="end" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="mantle" minThickness="10" maxThickness="25">
<import group="end" />
<filler block="minecraft:bedrock" ratio=".001" />
</shell>
<shell name="surface" minThickness="2" maxThickness="3">
<import group="end_surface" />
</shell>
</structure>
<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">
<for variable="gasMetadata" in="0,1,2,3,4,5,6,7,8,9,10,11">
<structure group="gascloud" name="bigCloud_%gasMetadata%" weight="1">
<metashell block="minecraft:glowstoneOff" minCount="10" maxCount="16" minRadius="5" relativeRadius="0.5" />
<shell name="mantle" minThickness="5" maxThickness="15">
<filler weight="1" block="WarpDrive:blockGas" metadata="%gasMetadata%" />
</shell>
</structure>
<structure group="gascloud" name="smallCloud_%gasMetadata%" weight="1">
<metashell block="minecraft:glowstoneOff" minCount="3" maxCount="7" minRadius="3" relativeRadius="0.5" />
<shell name="mantle" minThickness="2" maxThickness="8">
<filler weight="1" block="WarpDrive:blockGas" metadata="%gasMetadata%" />
</shell>
</structure>
</for>
<structure group="asteroid" name="ClusteredAsteroid" weight="3">
<metashell block="minecraft:iron_ore" minCount="6" maxCount="10" minRadius="2" relativeRadius="0.5" />
<shell name="mantle" minThickness="3" maxThickness="7">
<import group="overworld_common" />
<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" minCoreCount="1" maxCoreCount="3" relativeCoreRadius="0.1">
<shell name="mantle" minThickness="1" maxThickness="6" fillerSets="commonOres,uncommonOres">
<structure group="asteroid" name="SphericalAsteroid" weight="10">
<metashell block="minecraft:iron_ore" minCount="1" maxCount="3" minRadius="2" relativeRadius="0.5" />
<shell name="mantle" minThickness="2" maxThickness="6">
<import group="overworld_uncommon" />
<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" minCoreCount="1" maxCoreCount="2" relativeCoreRadius="0.1">
<shell name="mantle" minThickness="1" maxThickness="6" fillerSets="commonOres">
<structure group="asteroid" name="diamondGeode" weight="2">
<metashell block="minecraft:diamond_ore" minCount="1" maxCount="2" minRadius="2" relativeRadius="0.5" />
<shell name="mantle" minThickness="2" maxThickness="6">
<import group="overworld_rare" />
<filler weight="10" block="minecraft:stone" />
<filler weight="5" block="minecraft:cobblestone" />
</shell>
</structure>
</warpdriveWorldGeneration>
<structure group="asteroid" name="mini_overworld" weight="10">
<metashell block="minecraft:diamond_ore" minCount="1" maxCount="2" minRadius="2" relativeRadius="0.5" />
<shell name="mantle" minThickness="2" maxThickness="6">
<import group="overworld_allOres" name="stone" />
<filler weight="10" block="minecraft:stone" />
<filler weight="5" block="minecraft:cobblestone" />
</shell>
</structure>
<structure group="asteroid" name="mini_nether" ratio="0.04">
<metashell block="minecraft:diamond_ore" minCount="1" maxCount="2" minRadius="2" relativeRadius="0.5" />
<shell name="mantle" minThickness="2" maxThickness="6">
<import group="nether" />
<filler weight="10" block="minecraft:stone" />
<filler weight="5" block="minecraft:cobblestone" />
</shell>
</structure>
<structure group="asteroid" name="mini_end" ratio="0.028">
<metashell block="minecraft:diamond_ore" minCount="1" maxCount="2" minRadius="2" relativeRadius="0.5" />
<shell name="mantle" minThickness="2" maxThickness="6">
<import group="end" />
<filler weight="10" block="minecraft:stone" />
<filler weight="5" block="minecraft:cobblestone" />
</shell>
</structure>
</worldGeneration>

View file

@ -1,26 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE warpdriveWorldGeneration>
<warpdriveWorldGeneration version="1" mods="netherores">
<worldGeneration version="2"
xmlns="WarpDrive"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="WarpDrive warpDrive.xsd"
mods="netherores">
<structure group="moon" name="netherMoon" radius="20">
<shell name="core" minThickness="1" maxThickness="5" fillerSets="rareOres">
<filler weight="100" block="minecraft:iron_block" />
</shell>
<!-- Not implemented
<shell name="mantle" minThickness="6" maxThickness="30" fillerSets="nether">
</shell>
</structure>
<structure group="moon" name="netherMoonCorrupted" radius="20">
<shell name="core" minThickness="1" maxThickness="5" fillerSets="rareOres">
<filler weight="100" block="minecraft:iron_block" />
</shell>
<shell name="mantle" minThickness="6" maxThickness="30" fillerSets="nether">
<filler ratio=".3" block="minecraft:air" />
<filler ratio=".3" block="minecraft:netherbrick" />
</shell>
</structure>
</warpdriveWorldGeneration>
-->
</worldGeneration>