Added the Lavender Fields, fixed the height of regular trees in some biomes

This commit is contained in:
Adubbz 2015-04-18 19:46:47 +10:00
parent 035e96676a
commit 21555fb6ee
8 changed files with 647 additions and 14 deletions

View File

@ -18,6 +18,7 @@ public class BOPBiomes
public static Optional<BiomeGenBase> arctic = Optional.absent();
public static Optional<BiomeGenBase> crag = Optional.absent();
public static Optional<BiomeGenBase> flowerField = Optional.absent();
public static Optional<BiomeGenBase> lavenderFields = Optional.absent();
public static Optional<BiomeGenBase> originValley = Optional.absent();
public static Optional<BiomeGenBase> shrubland = Optional.absent();
public static Optional<BiomeGenBase> steppe = Optional.absent();

View File

@ -0,0 +1,76 @@
/*******************************************************************************
* Copyright 2015, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.biome.overworld;
import net.minecraft.block.BlockTallGrass;
import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos;
import net.minecraftforge.common.BiomeManager.BiomeType;
import biomesoplenty.api.biome.BOPBiome;
import biomesoplenty.api.biome.generation.GeneratorStage;
import biomesoplenty.api.biome.generation.GeneratorWeighted;
import biomesoplenty.api.block.BOPBlocks;
import biomesoplenty.api.block.BOPPlantEnums.AllPlants;
import biomesoplenty.api.block.BOPTreeEnums.AllTrees;
import biomesoplenty.api.block.BOPWoodEnums.AllWoods;
import biomesoplenty.common.block.BlockBOPFlower2;
import biomesoplenty.common.block.BlockBOPFlower2.FlowerType;
import biomesoplenty.common.block.BlockBOPLeaves;
import biomesoplenty.common.block.BlockBOPLeaves3;
import biomesoplenty.common.block.BlockBOPLeaves4;
import biomesoplenty.common.block.BlockBOPLog;
import biomesoplenty.common.block.BlockBOPLog3;
import biomesoplenty.common.block.BlockBOPPlant;
import biomesoplenty.common.block.BlockGem;
import biomesoplenty.common.block.BlockGem.GemType;
import biomesoplenty.common.world.feature.GeneratorFlora;
import biomesoplenty.common.world.feature.GeneratorGrass;
import biomesoplenty.common.world.feature.GeneratorOreSingle;
import biomesoplenty.common.world.feature.tree.GeneratorBasicTree;
import biomesoplenty.common.world.feature.tree.GeneratorBigTree;
public class BiomeGenLavenderFields extends BOPBiome
{
private static final Height biomeHeight = new Height(0.125F, 0.05F);
public BiomeGenLavenderFields()
{
this.setHeight(biomeHeight);
this.setColor(11035852);
this.setTemperatureRainfall(0.6F, 0.7F);
this.addWeight(BiomeType.WARM, 3);
this.addGenerator("lavender", GeneratorStage.FLOWERS, new GeneratorFlora(999, BOPBlocks.flower2.getDefaultState().withProperty(BlockBOPFlower2.VARIANT, FlowerType.LAVENDER)));
GeneratorWeighted treeGenerator = new GeneratorWeighted(1);
treeGenerator.add(3, new GeneratorBasicTree(1, false, 4, 7, BOPBlocks.log_3.getDefaultState().withProperty(BlockBOPLog.getVariantProperty(BlockBOPLog3.PAGENUM), AllWoods.JACARANDA), BOPBlocks.leaves_3.getDefaultState().withProperty(BlockBOPLeaves.getVariantProperty(BlockBOPLeaves3.PAGENUM), AllTrees.JACARANDA)));
treeGenerator.add(1, new GeneratorBigTree(1, false, Blocks.log.getDefaultState(), Blocks.leaves.getDefaultState()));
this.addGenerator("trees", GeneratorStage.TREE, treeGenerator);
GeneratorWeighted grassGenerator = new GeneratorWeighted(20);
grassGenerator.add(1, new GeneratorGrass(1, BlockBOPPlant.getVariantState(AllPlants.WHEATGRASS)));
grassGenerator.add(3, new GeneratorGrass(1, Blocks.tallgrass.getDefaultState().withProperty(BlockTallGrass.TYPE, BlockTallGrass.EnumType.GRASS)));
this.addGenerator("grass", GeneratorStage.GRASS, grassGenerator);
this.addGenerator("peridot", GeneratorStage.SAND, new GeneratorOreSingle(BOPBlocks.gem_ore.getDefaultState().withProperty(BlockGem.VARIANT, GemType.PERIDOT), 12, 4, 32));
}
@Override
public int getGrassColorAtPos(BlockPos pos)
{
return 10601325;
}
@Override
public int getFoliageColorAtPos(BlockPos pos)
{
return 10601325;
}
}

View File

@ -38,7 +38,7 @@ public class BiomeGenThicket extends BOPBiome
this.addWeight(BiomeType.COOL, 5);
GeneratorWeighted treeGenerator = new GeneratorWeighted(17);
treeGenerator.add(1, new GeneratorBasicTree(1, false, 4, 3, Blocks.log.getDefaultState(), Blocks.leaves.getDefaultState()));
treeGenerator.add(1, new GeneratorBasicTree(1, false, 4, 7, Blocks.log.getDefaultState(), Blocks.leaves.getDefaultState()));
treeGenerator.add(4, new GeneratorBush(1, Blocks.log.getDefaultState(), Blocks.leaves.getDefaultState()));
this.addGenerator("trees", GeneratorStage.TREE, treeGenerator);

View File

@ -21,6 +21,7 @@ import biomesoplenty.common.biome.overworld.BiomeGenAlps;
import biomesoplenty.common.biome.overworld.BiomeGenArctic;
import biomesoplenty.common.biome.overworld.BiomeGenCrag;
import biomesoplenty.common.biome.overworld.BiomeGenFlowerField;
import biomesoplenty.common.biome.overworld.BiomeGenLavenderFields;
import biomesoplenty.common.biome.overworld.BiomeGenOriginValley;
import biomesoplenty.common.biome.overworld.BiomeGenShrubland;
import biomesoplenty.common.biome.overworld.BiomeGenSteppe;
@ -53,6 +54,7 @@ public class ModBiomes
arctic = registerBiome(new BiomeGenArctic().setBiomeName("Arctic"), "arctic");
crag = registerBiome(new BiomeGenCrag().setBiomeName("Crag"), "crag");
flowerField = registerBiome(new BiomeGenFlowerField().setBiomeName("Flower Field"), "flower_field");
lavenderFields = registerBiome(new BiomeGenLavenderFields().setBiomeName("Lavender Fields"), "lavender_fields");
originValley = registerBiome(new BiomeGenOriginValley().setBiomeName("Origin Valley"), "origin_valley");
shrubland = registerBiome(new BiomeGenShrubland().setBiomeName("Shrubland"), "shrubland");
steppe = registerBiome(new BiomeGenSteppe().setBiomeName("Steppe"), "steppe");

View File

@ -18,6 +18,7 @@ import biomesoplenty.common.world.feature.GeneratorOreCluster;
import biomesoplenty.common.world.feature.GeneratorOreSingle;
import biomesoplenty.common.world.feature.GeneratorWaterside;
import biomesoplenty.common.world.feature.tree.GeneratorBasicTree;
import biomesoplenty.common.world.feature.tree.GeneratorBigTree;
import biomesoplenty.common.world.feature.tree.GeneratorBush;
public class ModGenerators
@ -29,6 +30,7 @@ public class ModGenerators
registerGenerator("weighted", GeneratorWeighted.class);
registerGenerator("weighted_entry", GeneratorWeightedEntry.class);
registerGenerator("basic_tree", GeneratorBasicTree.class);
registerGenerator("big_tree", GeneratorBigTree.class);
registerGenerator("bush", GeneratorBush.class);
registerGenerator("flora", GeneratorFlora.class);
registerGenerator("double_flora", GeneratorDoubleFlora.class);

View File

@ -34,19 +34,6 @@ public class GeneratorUtils
minHeight = maxHeight;
maxHeight = prevMinHeight;
}
else if (maxHeight == minHeight)
{
if (minHeight < 255)
{
//Increase max height to be higher than min height
++maxHeight;
}
else
{
//Decrease min height so that max is higher
--minHeight;
}
}
return Pair.of(minHeight, maxHeight);
}

View File

@ -317,6 +317,8 @@ public class GeneratorBasicTree extends GeneratorCustomizable
{
this.amountPerChunk = json.get("amount_per_chunk").getAsInt();
this.updateNeighbours = json.get("update_neighbours").getAsBoolean();
int minHeight = json.get("min_height").getAsInt();
int maxHeight = json.get("max_height").getAsInt();
Pair<Integer, Integer> heights = GeneratorUtils.validateMinMaxHeight(minHeight, maxHeight);
this.minHeight = heights.getLeft();
@ -325,5 +327,7 @@ public class GeneratorBasicTree extends GeneratorCustomizable
this.log = context.deserialize(json.get("log_state"), IBlockState.class);
this.leaves = context.deserialize(json.get("leaves_state"), IBlockState.class);
this.vine = context.deserialize(json.get("vine_state"), IBlockState.class);
System.out.println(amountPerChunk + " " + updateNeighbours + " " + minHeight + " " + maxHeight + " " + log + " " + leaves);
}
}

View File

@ -0,0 +1,561 @@
/*******************************************************************************
* Copyright 2015, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world.feature.tree;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import org.apache.commons.lang3.tuple.Pair;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLog;
import net.minecraft.block.BlockSapling;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.WorldGenBigTree;
import biomesoplenty.api.biome.generation.GeneratorCustomizable;
import biomesoplenty.common.util.biome.GeneratorUtils;
import com.google.common.collect.Lists;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
/*This class is heavily based on https://gist.github.com/grum/62cfdec0537e8db24eb3#file-bigtreefeature-java
additional information has been added from http://pastebin.com/XBLdGqXQ. This class has been cross-checked
against WorldGenBigTree to ensure any subsequent changes from Forge/Mojang have been included.*/
public class GeneratorBigTree extends GeneratorCustomizable
{
private Random random;
private World world;
private BlockPos origin;
private int height;
private int trunkHeight;
private double trunkHeightScale = 0.618;
private double branchSlope = 0.381;
private double widthScale = 1;
private double foliageDensity = 1;
private int trunkWidth = 1;
//private int heightVariance = 12;
private int foliageHeight = 4;
//Configurable fields
private int amountPerChunk;
private boolean updateNeighbours;
private int minHeight;
private int maxHeight;
private IBlockState log;
private IBlockState leaves;
private List<FoliageCoords> foliageCoords;
public GeneratorBigTree() {}
public GeneratorBigTree(int amountPerChunk, boolean updateNeighbours, int minHeight, int maxHeight, IBlockState log, IBlockState leaves)
{
this.amountPerChunk = amountPerChunk;
this.updateNeighbours = updateNeighbours;
Pair<Integer, Integer> heights = GeneratorUtils.validateMinMaxHeight(minHeight, maxHeight);
this.minHeight = heights.getLeft();
this.maxHeight = heights.getRight();
this.log = log;
this.leaves = leaves;
}
public GeneratorBigTree(int amountPerChunk, boolean updateNeighbours, IBlockState log, IBlockState leaves)
{
this(amountPerChunk, updateNeighbours, 5, 17, log, leaves);
}
protected void prepare()
{
// Populate the list of foliage cluster locations.
// Designed to be overridden in child classes to change basic
// tree properties (trunk width, branch angle, foliage density, etc..).
trunkHeight = (int) (height * trunkHeightScale);
if (trunkHeight >= height)
{
trunkHeight = height - 1;
}
// Define foliage clusters per y
int clustersPerY = (int) (1.382 + Math.pow(foliageDensity * height / 13.0, 2));
if (clustersPerY < 1) {
clustersPerY = 1;
}
final int trunkTop = origin.getY() + trunkHeight;
int relativeY = height - foliageHeight;
foliageCoords = Lists.newArrayList();
foliageCoords.add(new FoliageCoords(origin.up(relativeY), trunkTop));
for (; relativeY >= 0; relativeY--)
{
float treeShape = treeShape(relativeY);
if (treeShape < 0)
{
continue;
}
for (int i = 0; i < clustersPerY; i++)
{
final double radius = widthScale * treeShape * (random.nextFloat() + 0.328);
final double angle = random.nextFloat() * 2 * Math.PI;
final double x = radius * Math.sin(angle) + 0.5;
final double z = radius * Math.cos(angle) + 0.5;
final BlockPos checkStart = origin.add(x, relativeY - 1, z);
final BlockPos checkEnd = checkStart.up(foliageHeight);
// check the center column of the cluster for obstructions.
if (checkLine(checkStart, checkEnd) == -1)
{
// If the cluster can be created, check the branch path for obstructions.
final int dx = origin.getX() - checkStart.getX();
final int dz = origin.getZ() - checkStart.getZ();
final double height = checkStart.getY() - Math.sqrt(dx * dx + dz * dz) * branchSlope;
final int branchTop = height > trunkTop ? trunkTop : (int) height;
final BlockPos checkBranchBase = new BlockPos(origin.getX(), branchTop, origin.getZ());
// Now check the branch path
if (checkLine(checkBranchBase, checkStart) == -1)
{
// If the branch path is clear, add the position to the list of foliage positions
foliageCoords.add(new FoliageCoords(checkStart, checkBranchBase.getY()));
}
}
}
}
}
private void crossection(BlockPos pos, float radius, IBlockState state)
{
// Create a circular cross section.
//
// Used to nearly everything in the foliage, branches, and trunk.
// This is a good target for performance optimization.
// Passed values:
// pos is the center location of the cross section
// radius is the radius of the section from the center
// direction is the direction the cross section is pointed, 0 for x, 1
// for y, 2 for z material is the index number for the material to use
final int r = (int) (radius + 0.618);
for (int dx = -r; dx <= r; dx++)
{
for (int dz = -r; dz <= r; dz++)
{
if (Math.pow(Math.abs(dx) + 0.5, 2) + Math.pow(Math.abs(dz) + 0.5, 2) <= radius * radius)
{
BlockPos checkedPos = pos.add(dx, 0, dz);
IBlockState checkedState = this.world.getBlockState(checkedPos);
if (checkedState.getBlock().isAir(this.world, checkedPos) || checkedState.getBlock().isLeaves(this.world, checkedPos))
{
this.setBlockAndNotifyAdequately(world, checkedPos, state);
}
}
}
}
}
protected float treeShape(int y)
{
// Take the y position relative to the base of the tree.
// Return the distance the foliage should be from the trunk axis.
// Return a negative number if foliage should not be created at this
// height. This method is intended for overriding in child classes,
// allowing different shaped trees. This method should return a
// consistent value for each y (don't randomize).
if (y < height * 0.3f) {
return -1f;
}
final float radius = height / 2.0f;
final float adjacent = radius - y;
float distance = MathHelper.sqrt_float(radius * radius - adjacent * adjacent);
if (adjacent == 0) {
distance = radius;
} else if (Math.abs(adjacent) >= radius) {
return 0f;
}
// Alter this factor to change the overall width of the tree.
return distance * 0.5f;
}
protected float foliageShape(int y)
{
// Take the y position relative to the base of the foliage cluster.
// Return the radius of the cluster at this y
// Return a negative number if no foliage should be created at this
// level. This method is intended for overriding in child classes,
// allowing foliage of different sizes and shapes.
if (y < 0 || y >= foliageHeight)
{
return -1f;
}
//The following has been replaced as recommended by
//http://www.reddit.com/r/Minecraft/comments/1m97cw/while_you_are_all_crying_over_the_name_change_of/ccfgc3k
//The change should fix the decaying leaves
/*else if (y == 0 || y == foliageHeight - 1)
{
return 2f;
}*/
else if (y == 0 || y == foliageHeight - 2)
{
return 2f;
}
else if (y == foliageHeight - 1)
{
return 1.5f;
}
else
{
return 3f;
}
}
private void foliageCluster(BlockPos blockPos)
{
// Generate a cluster of foliage, with the base at blockPos
// The shape of the cluster is derived from foliageShape
// crossection is called to make each level.
for (int y = 0; y < foliageHeight; y++)
{
crossection(blockPos.up(y), foliageShape(y), this.leaves);
}
}
private void limb(BlockPos startPos, BlockPos endPos, IBlockState state)
{
// Create a limb from the start position to the end position.
// Used for creating the branches and trunk.
// Similar to checkLine, however it is setting rather than checking
//The distance between the two points, may be negative if the second pos is smaller
BlockPos delta = endPos.add(-startPos.getX(), -startPos.getY(), -startPos.getZ());
int steps = getSteps(delta);
//How much should be incremented with each iteration relative
//to the greatest distance which will have a value of 1.0F.
float dx = delta.getX() / (float) steps;
float dy = delta.getY() / (float) steps;
float dz = delta.getZ() / (float) steps;
//Iterates over all values between the start pos and end pos
for (int i = 0; i <= steps; i++)
{
//A delta position between the start pos and end pos. Increments are added to the x, y and z coords
//so that they meet their corresponding values in the end pos when j reaches the greatest distance. 0.5F
//is added to ensure the final point is reached.
BlockPos blockPos = startPos.add(.5f + i * dx, .5f + i * dy, .5f + i * dz);
BlockLog.EnumAxis logAxis = getLogAxis(startPos, blockPos);
this.setBlockAndNotifyAdequately(world, blockPos, state.withProperty(BlockLog.LOG_AXIS, logAxis));
}
}
private int getSteps(BlockPos pos)
{
final int absX = MathHelper.abs_int(pos.getX());
final int absY = MathHelper.abs_int(pos.getY());
final int absZ = MathHelper.abs_int(pos.getZ());
//Determine which axis has the greatest distance from the origin (0, 0, 0)
if (absZ > absX && absZ > absY) {
return absZ;
} else if (absY > absX) {
return absY;
}
return absX;
}
private int getGreatestDistance(BlockPos posIn)
{
int i = MathHelper.abs_int(posIn.getX());
int j = MathHelper.abs_int(posIn.getY());
int k = MathHelper.abs_int(posIn.getZ());
return k > i && k > j ? k : (j > i ? j : i);
}
private BlockLog.EnumAxis getLogAxis(BlockPos startPos, BlockPos endPos)
{
BlockLog.EnumAxis axis = BlockLog.EnumAxis.Y;
//Find the difference between the start and end pos
int xDiff = Math.abs(endPos.getX() - startPos.getX());
int zDiff = Math.abs(endPos.getZ() - startPos.getZ());
int maxDiff = Math.max(xDiff, zDiff);
//Check if the distance between the two positions is greater than 0 on either
//the x or the z axis. axis is set to the axis with the greatest distance
if (maxDiff > 0)
{
if (xDiff == maxDiff)
{
axis = BlockLog.EnumAxis.X;
}
else if (zDiff == maxDiff)
{
axis = BlockLog.EnumAxis.Z;
}
}
return axis;
}
private void makeFoliage()
{
// Create the tree foliage.
// Call foliageCluster at the correct locations
for (FoliageCoords foliageCoord : foliageCoords)
{
foliageCluster(foliageCoord);
}
}
protected boolean trimBranches(int localY)
{
// For larger trees, randomly "prune" the branches so there
// aren't too many.
// Return true if the branch should be created.
// This method is intended for overriding in child classes, allowing
// decent amounts of branches on very large trees.
// Can also be used to disable branches on some tree types, or
// make branches more sparse.
return localY >= height * 0.2;
}
private void makeTrunk()
{
// Create the trunk of the tree.
BlockPos start = origin;
BlockPos end = origin.up(trunkHeight);
IBlockState materialState = this.log;
limb(start, end, materialState);
if (trunkWidth == 2)
{
limb(start.east(), end.east(), materialState);
limb(start.east().south(), end.east().south(), materialState);
limb(start.south(), end.south(), materialState);
}
}
private void makeBranches()
{
for (FoliageCoords endCoord : foliageCoords)
{
int branchBase = endCoord.getBranchBase();
BlockPos baseCoord = new BlockPos(this.origin.getX(), branchBase, this.origin.getZ());
if (this.trimBranches(branchBase - this.origin.getY()))
{
this.limb(baseCoord, endCoord, this.log);
}
}
}
private int checkLine(BlockPos startPos, BlockPos endPos)
{
// Check from coordinates start to end (both inclusive) for blocks
// other than air and foliage If a block other than air and foliage is
// found, return the number of steps taken.
// If no block other than air and foliage is found, return -1.
// Examples:
// If the third block searched is stone, return 2
// If the first block searched is lava, return 0
//The distance between the two points, may be negative if the second pos is smaller
BlockPos delta = endPos.add(-startPos.getX(), -startPos.getY(), -startPos.getZ());
int steps = this.getGreatestDistance(delta);
//How much should be incremented with each iteration relative
//to the greatest distance which will have a value of 1.0F.
float dx = (float)delta.getX() / (float)steps;
float dy = (float)delta.getY() / (float)steps;
float dz = (float)delta.getZ() / (float)steps;
//Check if both positions are the same
if (steps == 0)
{
return -1;
}
//Iterates over all values between the start pos and end pos
for (int i = 0; i <= steps; i++)
{
//A delta position between the start pos and end pos. Increments are added to the x, y and z coords
//so that they meet their corresponding values in the end pos when j reaches the greatest distance. 0.5F
//is added to ensure the final point is reached.
BlockPos deltaPos = startPos.add((double)(0.5F + (float)i * dx), (double)(0.5F + (float)i * dy), (double)(0.5F + (float)i * dz));
if (!GeneratorUtils.canTreeReplace(world, deltaPos))
{
return i;
}
}
//The line is unobstructed
return -1;
}
@Override
public void scatter(World world, Random random, BlockPos pos)
{
for (int i = 0; i < amountPerChunk; i++)
{
int x = random.nextInt(16) + 8;
int z = random.nextInt(16) + 8;
BlockPos genPos = world.getHeight(pos.add(x, 0, z));
generate(world, random, genPos);
}
}
@Override
public boolean generate(World world, Random rand, BlockPos pos)
{
this.world = world;
this.origin = pos;
this.random = new Random(rand.nextLong());
if (this.height == 0)
{
this.height = random.nextInt(this.maxHeight - this.minHeight) + this.minHeight;
}
if (!this.checkLocation())
{
this.world = null; //Fix vanilla Mem leak, holds latest world
return false;
}
prepare();
makeFoliage();
makeTrunk();
makeBranches();
this.world = null; //Fix vanilla Mem leak, holds latest world
return true;
}
private boolean checkLocation()
{
BlockPos down = this.origin.down();
IBlockState state = this.world.getBlockState(down);
boolean isSoil = state.getBlock().canSustainPlant(this.world, down, EnumFacing.UP, ((BlockSapling)Blocks.sapling));
//Don't grow the tree here if the location can't sustain a sapling
if (!isSoil)
{
return false;
}
// Examine center column for how tall the tree can be.
int allowedHeight = checkLine(this.origin, this.origin.up(height - 1));
// If the set height is good, go with that
if (allowedHeight == -1) {
return true;
}
// If the space is too short, tell the build to abort
if (allowedHeight < 6) {
return false;
}
height = allowedHeight;
return true;
}
private void setBlockAndNotifyAdequately(World world, BlockPos pos, IBlockState state)
{
if (this.updateNeighbours)
{
world.setBlockState(pos, state, 3);
}
else
{
world.setBlockState(pos, state, 2);
}
}
private static class FoliageCoords extends BlockPos
{
private final int branchBase;
public FoliageCoords(BlockPos pos, int branchBase)
{
super(pos.getX(), pos.getY(), pos.getZ());
this.branchBase = branchBase;
}
public int getBranchBase()
{
return branchBase;
}
}
@Override
public void writeToJson(JsonObject json, JsonSerializationContext context)
{
json.addProperty("amount_per_chunk", this.amountPerChunk);
json.addProperty("update_neighbours", this.updateNeighbours);
json.addProperty("min_height", this.minHeight);
json.addProperty("max_height", this.maxHeight);
json.add("log_state", context.serialize(this.log));
json.add("leaves_state", context.serialize(this.leaves));
}
@Override
public void readFromJson(JsonObject json, JsonDeserializationContext context)
{
this.amountPerChunk = json.get("amount_per_chunk").getAsInt();
this.updateNeighbours = json.get("update_neighbours").getAsBoolean();
int minHeight = json.get("min_height").getAsInt();
int maxHeight = json.get("max_height").getAsInt();
Pair<Integer, Integer> heights = GeneratorUtils.validateMinMaxHeight(minHeight, maxHeight);
this.minHeight = heights.getLeft();
this.maxHeight = heights.getRight();
this.log = context.deserialize(json.get("log_state"), IBlockState.class);
this.leaves = context.deserialize(json.get("leaves_state"), IBlockState.class);
}
}