Added world generation resuming when reloading chunk

Code cleanup
This commit is contained in:
Unknown 2019-04-14 16:43:57 +02:00
parent 2bdbbc1ca7
commit 6131b23c02
11 changed files with 368 additions and 101 deletions

View file

@ -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

View file

@ -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();
}

View file

@ -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();
}
/**

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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));

View file

@ -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;