Added world generation resuming when reloading chunk
Code cleanup
This commit is contained in:
parent
2bdbbc1ca7
commit
6131b23c02
11 changed files with 368 additions and 101 deletions
|
@ -7,6 +7,9 @@ import cr0s.warpdrive.data.JumpBlock;
|
|||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import org.w3c.dom.Element;
|
||||
|
@ -89,7 +92,55 @@ public class Filler implements IXmlRepresentableUnit {
|
|||
}
|
||||
}
|
||||
|
||||
name = nameBlock + "@" + metadata + "{" + tagCompound + "}";
|
||||
name = nameBlock + "@" + metadata + (tagCompound == null ? "" : "{" + tagCompound + "}");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean loadFromName(final String nameToLoad) {
|
||||
final Pattern patternNameToLoadWithoutNBT = Pattern.compile("(.*)@(\\d*)");
|
||||
final Pattern patternNameToLoadWithNBT = Pattern.compile("(.*)@(\\d*)(\\{.*)");
|
||||
final boolean hasNBT = nameToLoad.contains("{");
|
||||
final Matcher matcher = hasNBT ? patternNameToLoadWithNBT.matcher(nameToLoad) : patternNameToLoadWithoutNBT.matcher(nameToLoad);
|
||||
if (!matcher.matches()) {
|
||||
throw new RuntimeException(String.format("Failed to load filler from name %s: unrecognized format",
|
||||
nameToLoad));
|
||||
}
|
||||
|
||||
final String nameBlock = matcher.group(1);
|
||||
block = Block.getBlockFromName(nameBlock);
|
||||
if (block == null) {
|
||||
WarpDrive.logger.warn(String.format("Failed to load filler from name %s: block %s is missing",
|
||||
nameToLoad, nameBlock));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get metadata attribute, defaults to 0
|
||||
metadata = 0;
|
||||
final String stringMetadata = matcher.group(2);
|
||||
if (!stringMetadata.isEmpty()) {
|
||||
try {
|
||||
metadata = Integer.parseInt(stringMetadata);
|
||||
} catch (final NumberFormatException exception) {
|
||||
throw new RuntimeException(String.format("Failed to load filler from name %s: invalid metadata %s",
|
||||
nameToLoad, stringMetadata));
|
||||
}
|
||||
}
|
||||
|
||||
// Get nbt attribute, default to null/none
|
||||
tagCompound = null;
|
||||
final String stringNBT = hasNBT ? matcher.group(3) : "";
|
||||
if (!stringNBT.isEmpty()) {
|
||||
try {
|
||||
tagCompound = JsonToNBT.getTagFromJson(stringNBT);
|
||||
} catch (final NBTException exception) {
|
||||
WarpDrive.logger.error(exception.getMessage());
|
||||
throw new RuntimeException(String.format("Failed to load filler from name %s: invalid nbt %s",
|
||||
nameToLoad, stringNBT));
|
||||
}
|
||||
}
|
||||
|
||||
name = nameBlock + "@" + metadata + (tagCompound == null ? "" : "{" + tagCompound + "}");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -151,7 +202,7 @@ public class Filler implements IXmlRepresentableUnit {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Filler(" + block.getTranslationKey() + "@" + metadata + ")";
|
||||
return "Filler(" + block.getRegistryName() + "@" + metadata + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,6 +3,7 @@ package cr0s.warpdrive.config;
|
|||
import cr0s.warpdrive.WarpDrive;
|
||||
import cr0s.warpdrive.api.IXmlRepresentable;
|
||||
import cr0s.warpdrive.api.IXmlRepresentableUnit;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
@ -11,6 +12,12 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.nbt.NBTTagString;
|
||||
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
|
||||
/**
|
||||
* Represents a set of 'units' that will be chosen randomly during world generation.
|
||||
**/
|
||||
|
@ -44,6 +51,67 @@ public class GenericSet<E extends IXmlRepresentableUnit> implements IXmlRepresen
|
|||
importGroups = new ArrayList<>();
|
||||
}
|
||||
|
||||
public GenericSet(final NBTTagCompound tagCompound, final E unitDefault, final String nameElementUnit) {
|
||||
if (tagCompound.hasKey("group")) {
|
||||
group = tagCompound.getString("group");
|
||||
} else {
|
||||
group = null;
|
||||
}
|
||||
name = tagCompound.getString("name");
|
||||
this.unitDefault = unitDefault;
|
||||
this.nameElementUnit = nameElementUnit;
|
||||
units = new XmlRandomCollection<>();
|
||||
units.loadFromNBT(tagCompound.getCompoundTag("units"), (String name) -> {
|
||||
if (unitDefault instanceof Filler) {
|
||||
final Filler filler = new Filler();
|
||||
if (filler.loadFromName(name)) {
|
||||
return (E) filler;
|
||||
}
|
||||
}
|
||||
return unitDefault; // TODO not implemented
|
||||
});
|
||||
|
||||
final NBTTagList listImportGroupNames = tagCompound.getTagList("importGroupNames", NBT.TAG_STRING);
|
||||
importGroupNames = new ArrayList<>();
|
||||
for (int indexImportGroupName = 0; indexImportGroupName < listImportGroupNames.tagCount(); indexImportGroupName++) {
|
||||
final String importGroupName = listImportGroupNames.getStringTagAt(indexImportGroupName);
|
||||
importGroupNames.add(importGroupName);
|
||||
}
|
||||
|
||||
final NBTTagList listImportGroups = tagCompound.getTagList("importGroups", NBT.TAG_STRING);
|
||||
importGroups = new ArrayList<>();
|
||||
for (int indexImportGroup = 0; indexImportGroup < listImportGroups.tagCount(); indexImportGroup++) {
|
||||
final String importGroup = listImportGroups.getStringTagAt(indexImportGroup);
|
||||
importGroups.add(importGroup);
|
||||
}
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(final NBTTagCompound tagCompound) {
|
||||
if (group != null) {
|
||||
tagCompound.setString("group", group);
|
||||
}
|
||||
tagCompound.setString("name", name);
|
||||
tagCompound.setTag("units", units.writeToNBT(new NBTTagCompound()));
|
||||
|
||||
if (!importGroupNames.isEmpty()) {
|
||||
final NBTTagList listImportGroupNames = new NBTTagList();
|
||||
for (final String importGroupName : importGroupNames) {
|
||||
listImportGroupNames.appendTag(new NBTTagString(importGroupName));
|
||||
}
|
||||
tagCompound.setTag("importGroupNames", listImportGroupNames);
|
||||
}
|
||||
|
||||
if (!importGroups.isEmpty()) {
|
||||
final NBTTagList listImportGroups = new NBTTagList();
|
||||
for (final String importGroup : importGroups) {
|
||||
listImportGroups.appendTag(new NBTTagString(importGroup));
|
||||
}
|
||||
tagCompound.setTag("importGroups", listImportGroups);
|
||||
}
|
||||
|
||||
return tagCompound;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return units.isEmpty();
|
||||
}
|
||||
|
|
|
@ -9,8 +9,13 @@ import java.util.NavigableMap;
|
|||
import java.util.Random;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.util.IStringSerializable;
|
||||
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
|
||||
/**
|
||||
* Collection of elements with ratios and weights. Helps to select element with controlled odds.
|
||||
*
|
||||
|
@ -19,12 +24,65 @@ import net.minecraft.util.IStringSerializable;
|
|||
* @param <E>
|
||||
**/
|
||||
public class RandomCollection<E extends IStringSerializable> {
|
||||
|
||||
public interface StringDeserializable<E extends IStringSerializable> {
|
||||
E deserialize(final String name);
|
||||
}
|
||||
|
||||
private final NavigableMap<Integer, E> weightMap = new TreeMap<>();
|
||||
private int totalWeight = 0;
|
||||
private final NavigableMap<Double, E> ratioMap = new TreeMap<>();
|
||||
private double totalRatio = 0;
|
||||
private final ArrayList<E> list = new ArrayList<>();
|
||||
|
||||
public void loadFromNBT(final NBTTagCompound tagCompound, final StringDeserializable<E> deserializer) {
|
||||
final NBTTagList tagListWeights = tagCompound.getTagList("weights", NBT.TAG_COMPOUND);
|
||||
for (final NBTBase tagBase : tagListWeights) {
|
||||
final NBTTagCompound tagCompoundWeight = (NBTTagCompound) tagBase;
|
||||
final int weight = tagCompoundWeight.getInteger("key");
|
||||
final String name = tagCompoundWeight.getString("name");
|
||||
final E object = deserializer.deserialize(name);
|
||||
addWeight(weight, object);
|
||||
}
|
||||
|
||||
final NBTTagList tagListRatios = tagCompound.getTagList("ratios", NBT.TAG_COMPOUND);
|
||||
for (final NBTBase tagBase : tagListRatios) {
|
||||
final NBTTagCompound tagCompoundWeight = (NBTTagCompound) tagBase;
|
||||
final double ratio = tagCompoundWeight.getDouble("key");
|
||||
final String name = tagCompoundWeight.getString("name");
|
||||
final E object = deserializer.deserialize(name);
|
||||
addRatio(ratio, object);
|
||||
}
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(final NBTTagCompound tagCompound) {
|
||||
final NBTTagList tagListWeights = new NBTTagList();
|
||||
int weightPrevious = 0;
|
||||
for (final Entry<Integer, E> entry : weightMap.entrySet()) {
|
||||
final NBTTagCompound tagCompoundWeight = new NBTTagCompound();
|
||||
final int weightEntry = entry.getKey();
|
||||
tagCompoundWeight.setInteger("key", weightEntry - weightPrevious);
|
||||
tagCompoundWeight.setString("name", entry.getValue().getName());
|
||||
tagListWeights.appendTag(tagCompoundWeight);
|
||||
weightPrevious = weightEntry;
|
||||
}
|
||||
tagCompound.setTag("weights", tagListWeights);
|
||||
|
||||
final NBTTagList tagListRatios = new NBTTagList();
|
||||
double ratioPrevious = 0.0D;
|
||||
for (final Entry<Double, E> entry : ratioMap.entrySet()) {
|
||||
final NBTTagCompound tagCompoundRatio = new NBTTagCompound();
|
||||
final double ratioEntry = entry.getKey();
|
||||
tagCompoundRatio.setDouble("key", ratioEntry - ratioPrevious);
|
||||
tagCompoundRatio.setString("name", entry.getValue().getName());
|
||||
tagListRatios.appendTag(tagCompoundRatio);
|
||||
ratioPrevious = ratioEntry;
|
||||
}
|
||||
tagCompound.setTag("ratios", tagListRatios);
|
||||
|
||||
return tagCompound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new object and its weight.
|
||||
*
|
||||
|
@ -132,17 +190,17 @@ public class RandomCollection<E extends IStringSerializable> {
|
|||
* @return Formatted string list separated by commas
|
||||
**/
|
||||
public String getNames() {
|
||||
String names = "";
|
||||
if (list.isEmpty()) {
|
||||
return "-none defined-";
|
||||
}
|
||||
final StringBuilder names = new StringBuilder();
|
||||
for (final E object : list) {
|
||||
if (!names.isEmpty()) {
|
||||
names += ", ";
|
||||
if (names.length() > 0) {
|
||||
names.append(", ");
|
||||
}
|
||||
names += object.getName();
|
||||
names.append(object.getName());
|
||||
}
|
||||
return names;
|
||||
return names.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,6 +12,7 @@ import net.minecraft.world.gen.feature.WorldGenerator;
|
|||
*
|
||||
*/
|
||||
public abstract class AbstractStructureInstance extends WorldGenerator {
|
||||
|
||||
protected AbstractStructure structure;
|
||||
protected HashMap<String,Double> variables = new HashMap<>();
|
||||
|
||||
|
@ -52,28 +53,31 @@ public abstract class AbstractStructureInstance extends WorldGenerator {
|
|||
}
|
||||
|
||||
public AbstractStructureInstance(final NBTTagCompound tagCompound) {
|
||||
// FIXME to be implemented
|
||||
|
||||
// get deployable
|
||||
// String deployableName = tagCompound.getString("wd_structureName");
|
||||
// get structure
|
||||
final String groupStructure = tagCompound.getString("group");
|
||||
final String nameStructure = tagCompound.getString("name");
|
||||
structure = StructureManager.getStructure(null, groupStructure, nameStructure);
|
||||
|
||||
// get variables values
|
||||
/*
|
||||
final NBTTagCompound tagVariables = tagCompound.getCompoundTag("wd_variables");
|
||||
final NBTTagList names = tagVariables.getTagList("x", 0);
|
||||
for (final Entry<String, Double> entry : tagVariables.getTagList("x", 0)) {
|
||||
tagVariables.setDouble(entry.getKey(), entry.getValue());
|
||||
final NBTTagCompound tagVariables = tagCompound.getCompoundTag("variables");
|
||||
for (final String key : tagVariables.getKeySet()) {
|
||||
final double value = tagVariables.getDouble(key);
|
||||
variables.put(key, value);
|
||||
}
|
||||
/**/
|
||||
}
|
||||
|
||||
public void WriteToNBT(final NBTTagCompound tagCompound) {
|
||||
tagCompound.setString("wd_structureGroup", structure.group);
|
||||
tagCompound.setString("wd_structureName", structure.name);
|
||||
final NBTTagCompound tagVariables = new NBTTagCompound();
|
||||
for (final Entry<String, Double> entry : variables.entrySet()) {
|
||||
tagVariables.setDouble(entry.getKey(), entry.getValue());
|
||||
public NBTTagCompound writeToNBT(final NBTTagCompound tagCompound) {
|
||||
tagCompound.setString("group", structure.group);
|
||||
tagCompound.setString("name", structure.name);
|
||||
|
||||
if (!variables.isEmpty()) {
|
||||
final NBTTagCompound tagVariables = new NBTTagCompound();
|
||||
for (final Entry<String, Double> entry : variables.entrySet()) {
|
||||
tagVariables.setDouble(entry.getKey(), entry.getValue());
|
||||
}
|
||||
tagCompound.setTag("variables", tagVariables);
|
||||
}
|
||||
tagCompound.setTag("wd_variables", tagVariables);
|
||||
|
||||
return tagCompound;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,10 @@ public class AsteroidFieldInstance extends AbstractStructureInstance {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void WriteToNBT(final NBTTagCompound tagCompound) {
|
||||
super.WriteToNBT(tagCompound);
|
||||
public NBTTagCompound writeToNBT(final NBTTagCompound tagCompound) {
|
||||
super.writeToNBT(tagCompound);
|
||||
// TODO not implemented
|
||||
return tagCompound;
|
||||
}
|
||||
|
||||
private static float binomialRandom(final World world) {
|
||||
|
|
|
@ -3,9 +3,9 @@ package cr0s.warpdrive.config.structures;
|
|||
import cr0s.warpdrive.Commons;
|
||||
import cr0s.warpdrive.LocalProfiler;
|
||||
import cr0s.warpdrive.WarpDrive;
|
||||
import cr0s.warpdrive.config.GenericSet;
|
||||
import cr0s.warpdrive.config.WarpDriveConfig;
|
||||
import cr0s.warpdrive.config.Filler;
|
||||
import cr0s.warpdrive.config.structures.Orb.OrbShell;
|
||||
import cr0s.warpdrive.data.VectorI;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
@ -41,8 +41,9 @@ public class MetaOrbInstance extends OrbInstance {
|
|||
|
||||
final int y2 = Math.min(WarpDriveConfig.SPACE_GENERATOR_Y_MAX_BORDER - totalThickness - (int) metaShell.radius,
|
||||
Math.max(blockPos.getY(), WarpDriveConfig.SPACE_GENERATOR_Y_MIN_BORDER + totalThickness + (int) metaShell.radius));
|
||||
final BlockPos blockPosUpdated = y2 == blockPos.getY() ? blockPos : new BlockPos(blockPos.getX(), y2, blockPos.getZ());
|
||||
if (((MetaOrb) structure).metaShell == null) {
|
||||
return super.generate(world, random, new BlockPos(blockPos.getX(), y2, blockPos.getZ()));
|
||||
return super.generate(world, random, blockPosUpdated);
|
||||
}
|
||||
|
||||
// generate an abstract form for the core
|
||||
|
@ -85,7 +86,7 @@ public class MetaOrbInstance extends OrbInstance {
|
|||
}
|
||||
|
||||
private void addShell(final World world, final VectorI location, final int radius) {
|
||||
final double sqRadius = radius * radius;
|
||||
final int sqRadius = radius * radius;
|
||||
final BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(location.x, location.y, location.z);
|
||||
// iterate all blocks within cube with side 2 * radius
|
||||
for (int x = location.x - radius; x <= location.x + radius; x++) {
|
||||
|
@ -99,8 +100,8 @@ public class MetaOrbInstance extends OrbInstance {
|
|||
mutableBlockPos.setPos(x, y, z);
|
||||
// if inside radius
|
||||
if (sqRange <= sqRadius && isReplaceableOreGen(world, mutableBlockPos)) {
|
||||
final OrbShell shell = getShellForSqRadius(sqRange);
|
||||
final Filler filler = shell.getRandomUnit(world.rand);
|
||||
final GenericSet<Filler> fillerSet = getFillerSetFromSquareRange(sqRange);
|
||||
final Filler filler = fillerSet.getRandomUnit(world.rand);
|
||||
filler.setBlock(world, mutableBlockPos);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,13 +71,11 @@ public class Orb extends AbstractStructure {
|
|||
|
||||
public class OrbShell extends GenericSet<Filler> {
|
||||
|
||||
private final String parentFullName;
|
||||
protected int minThickness;
|
||||
protected int maxThickness;
|
||||
|
||||
public OrbShell(final String parentFullName, final String name) {
|
||||
super(null, name, Filler.DEFAULT, "filler");
|
||||
this.parentFullName = parentFullName;
|
||||
super(parentFullName, name, Filler.DEFAULT, "filler");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,7 +92,7 @@ public class Orb extends AbstractStructure {
|
|||
final GenericSet<Filler> fillerSet = WarpDriveConfig.FillerManager.getGenericSet(importGroupName);
|
||||
if (fillerSet == null) {
|
||||
WarpDrive.logger.warn(String.format("Skipping missing FillerSet %s in shell %s:%s",
|
||||
importGroupName, parentFullName, name));
|
||||
importGroupName, group, name));
|
||||
} else {
|
||||
loadFrom(fillerSet);
|
||||
}
|
||||
|
@ -104,7 +102,7 @@ public class Orb extends AbstractStructure {
|
|||
for (final String importGroup : getImportGroups()) {
|
||||
if (!WarpDriveConfig.FillerManager.doesGroupExist(importGroup)) {
|
||||
WarpDrive.logger.warn(String.format("An invalid FillerSet group %s is referenced in shell %s:%s",
|
||||
importGroup, parentFullName, name));
|
||||
importGroup, group, name));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,26 +111,26 @@ public class Orb extends AbstractStructure {
|
|||
minThickness = Integer.parseInt(element.getAttribute("minThickness"));
|
||||
} catch (final NumberFormatException exception) {
|
||||
throw new InvalidXmlException(String.format("Invalid minThickness in shell %s of structure %s",
|
||||
name, parentFullName));
|
||||
name, group));
|
||||
}
|
||||
|
||||
try {
|
||||
maxThickness = Integer.parseInt(element.getAttribute("maxThickness"));
|
||||
} catch (final NumberFormatException exception) {
|
||||
throw new InvalidXmlException(String.format("Invalid maxThickness in shell %s of structure %s",
|
||||
name, parentFullName));
|
||||
name, group));
|
||||
}
|
||||
|
||||
if (maxThickness < minThickness) {
|
||||
throw new InvalidXmlException(String.format("Invalid maxThickness %d lower than minThickness %s in shell %s of orb %s",
|
||||
maxThickness, minThickness, name, parentFullName));
|
||||
maxThickness, minThickness, name, group));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public OrbShell instantiate(final Random random) {
|
||||
final OrbShell orbShell = new OrbShell(parentFullName, name);
|
||||
final OrbShell orbShell = new OrbShell(group, name);
|
||||
orbShell.minThickness = minThickness;
|
||||
orbShell.maxThickness = maxThickness;
|
||||
try {
|
||||
|
@ -141,24 +139,24 @@ public class Orb extends AbstractStructure {
|
|||
final GenericSet<Filler> fillerSet = WarpDriveConfig.FillerManager.getRandomSetFromGroup(random, importGroup);
|
||||
if (fillerSet == null) {
|
||||
WarpDrive.logger.warn(String.format("Ignoring invalid group %s in shell %s of structure %s",
|
||||
importGroup, name, parentFullName));
|
||||
importGroup, name, group));
|
||||
continue;
|
||||
}
|
||||
if (WarpDriveConfig.LOGGING_WORLD_GENERATION) {
|
||||
WarpDrive.logger.info(String.format("Filling %s:%s with %s:%s",
|
||||
parentFullName, name, importGroup, fillerSet.getName()));
|
||||
group, name, importGroup, fillerSet.getName()));
|
||||
}
|
||||
orbShell.loadFrom(fillerSet);
|
||||
}
|
||||
} catch (final Exception exception) {
|
||||
exception.printStackTrace();
|
||||
WarpDrive.logger.error(String.format("Failed to instantiate shell %s from structure %s",
|
||||
name, parentFullName));
|
||||
name, group));
|
||||
}
|
||||
if (orbShell.isEmpty()) {
|
||||
if (WarpDriveConfig.LOGGING_WORLD_GENERATION) {
|
||||
WarpDrive.logger.info(String.format("Ignoring empty shell %s in structure %s",
|
||||
name, parentFullName));
|
||||
name, group));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package cr0s.warpdrive.config.structures;
|
||||
|
||||
import cr0s.warpdrive.Commons;
|
||||
import cr0s.warpdrive.config.Filler;
|
||||
import cr0s.warpdrive.config.GenericSet;
|
||||
import cr0s.warpdrive.config.WarpDriveConfig;
|
||||
import cr0s.warpdrive.config.structures.Orb.OrbShell;
|
||||
import cr0s.warpdrive.world.EntitySphereGen;
|
||||
|
@ -8,34 +10,41 @@ import cr0s.warpdrive.world.EntityStarCore;
|
|||
import cr0s.warpdrive.world.WorldGenSmallShip;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.minecraftforge.common.util.Constants;
|
||||
|
||||
public class OrbInstance extends AbstractStructureInstance {
|
||||
|
||||
protected OrbShell[] orbShells;
|
||||
protected int[] orbShellThicknesses;
|
||||
protected ArrayList<GenericSet<Filler>> orbShellInstances;
|
||||
private int[] orbShellThicknesses;
|
||||
protected int totalThickness;
|
||||
protected int minThickness;
|
||||
protected String schematicName;
|
||||
|
||||
// internal look-up table to accelerate computations
|
||||
private OrbShell[] sqRadiusToOrbShell;
|
||||
private ArrayList<GenericSet<Filler>> sqRadiusToOrbShell;
|
||||
|
||||
public OrbInstance(final Orb orb, final Random random) {
|
||||
super(orb, random);
|
||||
orbShells = new OrbShell[orb.orbShells.length];
|
||||
|
||||
orbShellInstances = new ArrayList<>(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++) {
|
||||
final OrbShell orbShell = orb.orbShells[orbShellIndexIn].instantiate(random);
|
||||
// skip if it's an empty filler set
|
||||
if (orbShell != null) {
|
||||
orbShells[orbShellIndexOut] = orbShell;
|
||||
orbShellInstances.add(orbShell);
|
||||
final int thickness = Commons.randomRange(random, orbShell.minThickness, orbShell.maxThickness);
|
||||
orbShellThicknesses[orbShellIndexOut] = thickness;
|
||||
totalThickness += thickness;
|
||||
|
@ -43,31 +52,84 @@ public class OrbInstance extends AbstractStructureInstance {
|
|||
orbShellIndexOut++;
|
||||
}
|
||||
}
|
||||
// resize array in case we had one or more empty filler set
|
||||
if (orbShellThicknesses.length != orbShellIndexOut) {
|
||||
orbShellThicknesses = Arrays.copyOf(orbShellThicknesses, 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];
|
||||
schematicName = orb.schematicName;
|
||||
|
||||
constructionFinalizer();
|
||||
}
|
||||
|
||||
private void constructionFinalizer() {
|
||||
final int sqRadius = totalThickness * totalThickness;
|
||||
sqRadiusToOrbShell = new ArrayList<>(sqRadius);
|
||||
for (int sqRange = 0; sqRange < sqRadius; sqRange++) {// FIXME should we loop the orb shells instead of the range here?
|
||||
int range = 0;
|
||||
for (int indexShell = 0; indexShell < orbShellInstances.size(); indexShell++) {
|
||||
range += orbShellThicknesses[indexShell];
|
||||
if (sqRange <= range * range) {
|
||||
sqRadiusToOrbShell.add(orbShellInstances.get(indexShell));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schematicName = orb.schematicName;
|
||||
}
|
||||
|
||||
public OrbInstance(final NBTTagCompound tagCompound) {
|
||||
super(tagCompound);
|
||||
// TODO not implemented
|
||||
|
||||
final NBTTagList listOrbShells = tagCompound.getTagList("orbShellInstances", Constants.NBT.TAG_COMPOUND);
|
||||
if (listOrbShells.isEmpty()) {
|
||||
throw new RuntimeException(String.format("Empty orbShellInstances list isn't supported: %s",
|
||||
tagCompound));
|
||||
}
|
||||
orbShellInstances = new ArrayList<>(listOrbShells.tagCount());
|
||||
for (int indexOrbShell = 0; indexOrbShell < listOrbShells.tagCount(); indexOrbShell++) {
|
||||
final NBTTagCompound tagCompoundOrbShell = listOrbShells.getCompoundTagAt(indexOrbShell);
|
||||
final GenericSet<Filler> orbShell = new GenericSet<>(tagCompoundOrbShell, Filler.DEFAULT, "filler");
|
||||
orbShellInstances.add(orbShell);
|
||||
}
|
||||
orbShellThicknesses = tagCompound.getIntArray("orbShellThicknesses");
|
||||
if (orbShellInstances.size() != orbShellThicknesses.length) {
|
||||
throw new RuntimeException(String.format("Inconsistent orbShell and thicknesses sizes: %d != %d\n%s",
|
||||
orbShellInstances.size(), orbShellThicknesses.length, tagCompound));
|
||||
}
|
||||
totalThickness = tagCompound.getInteger("totalThickness");
|
||||
minThickness = tagCompound.getInteger("minThickness");
|
||||
|
||||
if (tagCompound.hasKey("schematicName")) {
|
||||
schematicName = tagCompound.getString("schematicName");
|
||||
} else {
|
||||
schematicName = null;
|
||||
}
|
||||
|
||||
constructionFinalizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void WriteToNBT(final NBTTagCompound tagCompound) {
|
||||
super.WriteToNBT(tagCompound);
|
||||
// TODO not implemented
|
||||
public NBTTagCompound writeToNBT(final NBTTagCompound tagCompound) {
|
||||
super.writeToNBT(tagCompound);
|
||||
|
||||
final NBTTagList listOrbShells = new NBTTagList();
|
||||
if (orbShellInstances.isEmpty()) {
|
||||
throw new RuntimeException(String.format("Empty orbShellInstances list isn't supported in %s",
|
||||
this));
|
||||
}
|
||||
for (final GenericSet<Filler> orbShellInstance : orbShellInstances) {
|
||||
final NBTTagCompound tagCompoundOrbShell = orbShellInstance.writeToNBT(new NBTTagCompound());
|
||||
listOrbShells.appendTag(tagCompoundOrbShell);
|
||||
}
|
||||
tagCompound.setTag("orbShellInstances", listOrbShells);
|
||||
tagCompound.setIntArray("orbShellThicknesses", orbShellThicknesses);
|
||||
tagCompound.setInteger("totalThickness", totalThickness);
|
||||
tagCompound.setInteger("minThickness", minThickness);
|
||||
if (schematicName != null) {
|
||||
tagCompound.setString("schematicName", schematicName);
|
||||
}
|
||||
|
||||
return tagCompound;
|
||||
}
|
||||
|
||||
public int getTotalThickness() {
|
||||
|
@ -79,8 +141,9 @@ public class OrbInstance extends AbstractStructureInstance {
|
|||
final boolean hasShip = schematicName != null && !schematicName.isEmpty();
|
||||
final int y2 = Math.min(WarpDriveConfig.SPACE_GENERATOR_Y_MAX_BORDER - totalThickness,
|
||||
Math.max(blockPos.getY(), WarpDriveConfig.SPACE_GENERATOR_Y_MIN_BORDER + totalThickness));
|
||||
final BlockPos blockPosUpdated = y2 == blockPos.getY() ? blockPos : new BlockPos(blockPos.getX(), y2, blockPos.getZ());
|
||||
if (hasShip) {
|
||||
new WorldGenSmallShip(random.nextFloat() < 0.2F, false).generate(world, random, new BlockPos(blockPos.getX(), y2, blockPos.getZ()));
|
||||
new WorldGenSmallShip(random.nextFloat() < 0.2F, false).generate(world, random, blockPosUpdated);
|
||||
}
|
||||
final EntitySphereGen entitySphereGen = new EntitySphereGen(world, blockPos.getX(), y2, blockPos.getZ(), this, !hasShip);
|
||||
world.spawnEntity(entitySphereGen);
|
||||
|
@ -90,12 +153,11 @@ public class OrbInstance extends AbstractStructureInstance {
|
|||
return true;
|
||||
}
|
||||
|
||||
public OrbShell getShellForSqRadius(final double sqRadius) {
|
||||
final int intSqRadius = (int) Math.round(sqRadius);
|
||||
if (intSqRadius < sqRadiusToOrbShell.length) {
|
||||
return sqRadiusToOrbShell[intSqRadius];
|
||||
public GenericSet<Filler> getFillerSetFromSquareRange(final int sqRadius) {
|
||||
if (sqRadius < sqRadiusToOrbShell.size()) {
|
||||
return sqRadiusToOrbShell.get(sqRadius);
|
||||
} else {
|
||||
return sqRadiusToOrbShell[sqRadiusToOrbShell.length - 1];
|
||||
return sqRadiusToOrbShell.get(sqRadiusToOrbShell.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,9 +60,10 @@ public class SchematicInstance extends AbstractStructureInstance {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void WriteToNBT(final NBTTagCompound tagCompound) {
|
||||
super.WriteToNBT(tagCompound);
|
||||
public NBTTagCompound writeToNBT(final NBTTagCompound tagCompound) {
|
||||
super.writeToNBT(tagCompound);
|
||||
// TODO not implemented
|
||||
return tagCompound;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package cr0s.warpdrive.event;
|
||||
|
||||
import cr0s.warpdrive.config.GenericSet;
|
||||
import cr0s.warpdrive.data.CelestialObjectManager;
|
||||
import cr0s.warpdrive.config.WarpDriveConfig;
|
||||
import cr0s.warpdrive.config.Filler;
|
||||
import cr0s.warpdrive.config.structures.Orb.OrbShell;
|
||||
import cr0s.warpdrive.config.structures.OrbInstance;
|
||||
import cr0s.warpdrive.config.structures.StructureGroup;
|
||||
import cr0s.warpdrive.data.CelestialObject;
|
||||
|
@ -58,10 +58,10 @@ public class CommonWorldGenerator implements IWorldGenerator {
|
|||
@Deprecated
|
||||
public static void generateSphereDirect(
|
||||
final OrbInstance orbInstance, final World world, final int xCoord, final int yCoord, final int zCoord) {
|
||||
final double radiusC = orbInstance.getTotalThickness() + 0.5D; // Radius from center of block
|
||||
final double radiusSq = radiusC * radiusC; // Optimization to avoid square roots...
|
||||
final double dRadius = orbInstance.getTotalThickness() + 0.5D; // Radius from center of block
|
||||
final double dSqRadius = dRadius * dRadius; // Optimization to avoid square roots...
|
||||
// sphere
|
||||
final int ceilRadius = (int) Math.ceil(radiusC);
|
||||
final int ceilRadius = (int) Math.ceil(dRadius);
|
||||
|
||||
// Pass the cube and check points for sphere equation x^2 + y^2 + z^2 = r^2
|
||||
final BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(xCoord, yCoord, zCoord);
|
||||
|
@ -71,18 +71,18 @@ public class CommonWorldGenerator implements IWorldGenerator {
|
|||
final double dX2Y2 = dX2 + (y + 0.5D) * (y + 0.5D);
|
||||
for (int z = 0; z <= ceilRadius; z++) {
|
||||
final double dZ2 = (z + 0.5D) * (z + 0.5D);
|
||||
final double dSq = dX2Y2 + dZ2; // squared distance from current position
|
||||
final double dSqRange = dX2Y2 + dZ2; // squared distance from current position
|
||||
|
||||
// Skip too far blocks
|
||||
if (dSq > radiusSq) {
|
||||
if (dSqRange > dSqRadius) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Place blocks
|
||||
// cheat by using axial symmetry so we don't create random numbers too frequently
|
||||
|
||||
final OrbShell orbShell = orbInstance.getShellForSqRadius(dSq);
|
||||
final Filler filler = orbShell.getRandomUnit(world.rand);
|
||||
final int intSqRange = (int) Math.round(dSqRange);
|
||||
final GenericSet<Filler> fillerSet = orbInstance.getFillerSetFromSquareRange(intSqRange);
|
||||
final Filler filler = fillerSet.getRandomUnit(world.rand);
|
||||
filler.setBlock(world, mutableBlockPos.setPos(xCoord + x, yCoord + y, zCoord + z));
|
||||
filler.setBlock(world, mutableBlockPos.setPos(xCoord - x, yCoord + y, zCoord + z));
|
||||
filler.setBlock(world, mutableBlockPos.setPos(xCoord + x, yCoord - y, zCoord + z));
|
||||
|
|
|
@ -2,7 +2,8 @@ package cr0s.warpdrive.world;
|
|||
|
||||
import cr0s.warpdrive.LocalProfiler;
|
||||
import cr0s.warpdrive.WarpDrive;
|
||||
import cr0s.warpdrive.config.structures.Orb.OrbShell;
|
||||
import cr0s.warpdrive.config.Filler;
|
||||
import cr0s.warpdrive.config.GenericSet;
|
||||
import cr0s.warpdrive.config.structures.OrbInstance;
|
||||
import cr0s.warpdrive.data.JumpBlock;
|
||||
|
||||
|
@ -88,14 +89,9 @@ public final class EntitySphereGen extends Entity {
|
|||
this.posZ = z;
|
||||
this.orbInstance = orbInstance;
|
||||
this.gasColor = world.rand.nextInt(12);
|
||||
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<>(this.pregenSize);
|
||||
isSurfaces = new ArrayList<>(this.pregenSize);
|
||||
this.ticksDelay = world.rand.nextInt(60);
|
||||
this.replace = replace;
|
||||
|
||||
constructionFinalizer();
|
||||
}
|
||||
|
||||
public void killEntity() {
|
||||
|
@ -191,17 +187,20 @@ public final class EntitySphereGen extends Entity {
|
|||
for (int y = 0; y <= ceilRadius; y++) {
|
||||
final double x2y2 = x2 + (y + 0.5D) * (y + 0.5D);
|
||||
for (int z = 0; z <= ceilRadius; z++) {
|
||||
final double sqRange = x2y2 + (z + 0.5D) * (z + 0.5D); // Square distance from current position to center
|
||||
final double dSqRange = x2y2 + (z + 0.5D) * (z + 0.5D); // Square distance from current position to center
|
||||
|
||||
// Skip too far blocks
|
||||
if (sqRange > sqRadiusHigh) {
|
||||
if (dSqRange > sqRadiusHigh) {
|
||||
continue;
|
||||
}
|
||||
final boolean isSurface = sqRange > sqRadiusLow;
|
||||
final boolean isSurface = dSqRange > sqRadiusLow;
|
||||
|
||||
// Add blocks to memory
|
||||
final OrbShell orbShell = orbInstance.getShellForSqRadius(sqRange);
|
||||
// WarpDrive.logger.info(String.format("sqRange %d sqRadius %d", sqRange, sqRadius));
|
||||
final int intSqRadius = (int) Math.round(dSqRange);
|
||||
final GenericSet<Filler> orbShell = orbInstance.getFillerSetFromSquareRange(intSqRadius);
|
||||
|
||||
// WarpDrive.logger.info(String.format("dSqRange %.3f sqRadiusHigh %.3f %.3f",
|
||||
// dSqRange, sqRadiusHigh, sqRadiusLow));
|
||||
addBlock(isSurface, new JumpBlock(orbShell.getRandomUnit(rand), xCoord + x, yCoord + y, zCoord + z));
|
||||
if (x != 0) {
|
||||
addBlock(isSurface, new JumpBlock(orbShell.getRandomUnit(rand), xCoord - x, yCoord + y, zCoord + z));
|
||||
|
@ -257,13 +256,42 @@ public final class EntitySphereGen extends Entity {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void readEntityFromNBT(@Nonnull final NBTTagCompound tagCompound) {
|
||||
// FIXME not implemented
|
||||
protected void entityInit() {
|
||||
noClip = true;
|
||||
}
|
||||
|
||||
private void constructionFinalizer() {
|
||||
radius = orbInstance.getTotalThickness();
|
||||
pregenSize = (int) Math.ceil(Math.PI * 4.0F / 3.0F * Math.pow(radius + 1, 3));
|
||||
blocks = new ArrayList<>(this.pregenSize);
|
||||
isSurfaces = new ArrayList<>(this.pregenSize);
|
||||
|
||||
state = STATE_SAVING;
|
||||
ticksDelay = world.rand.nextInt(60);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void entityInit() {
|
||||
noClip = true;
|
||||
public void readEntityFromNBT(@Nonnull final NBTTagCompound tagCompound) {
|
||||
xCoord = tagCompound.getInteger("warpdrive:xCoord");
|
||||
yCoord = tagCompound.getInteger("warpdrive:yCoord");
|
||||
zCoord = tagCompound.getInteger("warpdrive:zCoord");
|
||||
orbInstance = new OrbInstance(tagCompound.getCompoundTag("warpdrive:orbInstance"));
|
||||
gasColor = tagCompound.getInteger("warpdrive:gasColor");
|
||||
replace = tagCompound.getBoolean("warpdrive:replace");
|
||||
|
||||
constructionFinalizer();
|
||||
WarpDrive.logger.info(String.format("%s Reloaded from NBT",
|
||||
this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEntityToNBT(final NBTTagCompound tagCompound) {
|
||||
tagCompound.setInteger("warpdrive:xCoord", xCoord);
|
||||
tagCompound.setInteger("warpdrive:yCoord", yCoord);
|
||||
tagCompound.setInteger("warpdrive:zCoord", zCoord);
|
||||
tagCompound.setTag("warpdrive:orbInstance", orbInstance.writeToNBT(new NBTTagCompound()));
|
||||
tagCompound.setInteger("warpdrive:gasColor", gasColor);
|
||||
tagCompound.setBoolean("warpdrive:replace", replace);
|
||||
}
|
||||
|
||||
// override to skip the block bounding override on client side
|
||||
|
@ -274,11 +302,6 @@ public final class EntitySphereGen extends Entity {
|
|||
this.setRotation(yaw, pitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeEntityToNBT(@Nonnull final NBTTagCompound tagCompound) {
|
||||
// FIXME not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderInPass(final int pass) {
|
||||
return false;
|
||||
|
|
Loading…
Reference in a new issue