diff --git a/src/main/java/gregtech/api/worldgen/generator/WorldGeneratorImpl.java b/src/main/java/gregtech/api/worldgen/generator/WorldGeneratorImpl.java index e9386e2e061..d3e091bce86 100644 --- a/src/main/java/gregtech/api/worldgen/generator/WorldGeneratorImpl.java +++ b/src/main/java/gregtech/api/worldgen/generator/WorldGeneratorImpl.java @@ -1,16 +1,8 @@ package gregtech.api.worldgen.generator; -import gregtech.common.ConfigHolder; -import gregtech.common.worldgen.WorldGenRubberTree; - -import net.minecraft.init.Biomes; -import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.IChunkProvider; import net.minecraft.world.gen.IChunkGenerator; -import net.minecraftforge.common.BiomeDictionary; import net.minecraftforge.fml.common.IWorldGenerator; import java.util.Random; @@ -30,12 +22,6 @@ public void generate(Random random, int chunkX, int chunkZ, World world, IChunkG int selfGridX = Math.floorDiv(chunkX, GRID_SIZE_X); int selfGridZ = Math.floorDiv(chunkZ, GRID_SIZE_Z); generateInternal(world, selfGridX, selfGridZ, chunkX, chunkZ, random); - - long rubberTreeSeed = random.nextLong(); - if (!ConfigHolder.worldgen.disableRubberTreeGeneration) { - generateRubberTree(random, rubberTreeSeed, chunkProvider.provideChunk(chunkX, chunkZ), - ConfigHolder.worldgen.rubberTreeRateIncrease); - } } private static void generateInternal(World world, int selfGridX, int selfGridZ, int chunkX, int chunkZ, @@ -50,36 +36,4 @@ private static void generateInternal(World world, int selfGridX, int selfGridZ, } } } - - private static void generateRubberTree(Random random, long seed, Chunk chunk, double baseScale) { - random.setSeed(seed); - Biome[] biomes = new Biome[4]; - BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); - int seaLevel = chunk.getWorld().getSeaLevel(); - for (int i = 0; i < 4; i++) { - int x = chunk.x * 16 + 8 + (i & 0x1) * 15; - int z = chunk.z * 16 + 8 + ((i & 0x2) >>> 1) * 15; - biomes[i] = chunk.getWorld().getBiomeProvider().getBiome(pos.setPos(x, seaLevel, z), Biomes.PLAINS); - } - int rubberTrees = 0; - for (Biome biome : biomes) { - if (biome != null) { - if (BiomeDictionary.hasType(biome, BiomeDictionary.Type.SWAMP)) - rubberTrees += random.nextInt(10) + 5; - if (BiomeDictionary.hasType(biome, BiomeDictionary.Type.FOREST) || - BiomeDictionary.hasType(biome, BiomeDictionary.Type.JUNGLE)) - rubberTrees += random.nextInt(5) + 1; - } - } - rubberTrees = (int) Math.round(rubberTrees * baseScale); - rubberTrees /= 2; - if (rubberTrees > 0 && random.nextInt(100) < rubberTrees) { - for (int j = 0; j < rubberTrees; j++) { - pos.setPos(chunk.x * 16 + random.nextInt(16), seaLevel, chunk.z * 16 + random.nextInt(16)); - if (!WorldGenRubberTree.WORLD_GEN_INSTANCE.generateImpl(chunk.getWorld(), random, pos)) { - rubberTrees -= 3; - } - } - } - } } diff --git a/src/main/java/gregtech/common/blocks/wood/BlockRubberSapling.java b/src/main/java/gregtech/common/blocks/wood/BlockRubberSapling.java index 653a31fc9a8..77d9c05c132 100644 --- a/src/main/java/gregtech/common/blocks/wood/BlockRubberSapling.java +++ b/src/main/java/gregtech/common/blocks/wood/BlockRubberSapling.java @@ -1,18 +1,20 @@ package gregtech.common.blocks.wood; import gregtech.common.creativetab.GTCreativeTabs; -import gregtech.common.worldgen.WorldGenRubberTree; +import gregtech.worldgen.impl.WorldGenRubberTree; import net.minecraft.block.BlockBush; import net.minecraft.block.IGrowable; import net.minecraft.block.SoundType; import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.EnumPlantType; +import net.minecraftforge.event.terraingen.TerrainGen; import org.jetbrains.annotations.NotNull; @@ -22,7 +24,7 @@ public class BlockRubberSapling extends BlockBush implements IGrowable { - protected static final AxisAlignedBB SAPLING_AABB = new AxisAlignedBB(0.1, 0.0D, 0.1, 0.9, 0.8, 0.9); + private static final AxisAlignedBB SAPLING_AABB = new AxisAlignedBB(0.1, 0.0D, 0.1, 0.9, 0.8, 0.9); public BlockRubberSapling() { this.setDefaultState(this.blockState.getBaseState() @@ -40,13 +42,21 @@ protected BlockStateContainer createBlockState() { } @Override - public void updateTick(World worldIn, @NotNull BlockPos pos, @NotNull IBlockState state, @NotNull Random rand) { + public void updateTick(@NotNull World worldIn, @NotNull BlockPos pos, @NotNull IBlockState state, + @NotNull Random rand) { if (!worldIn.isRemote) { super.updateTick(worldIn, pos, state, rand); - if (!worldIn.isAreaLoaded(pos, 1)) + if (!worldIn.isAreaLoaded(pos, 1)) { return; + } + + // longer than the vanilla growth requirement if (worldIn.getLightFromNeighbors(pos.up()) >= 9 && rand.nextInt(30) == 0) { - this.grow(worldIn, rand, pos, state); + if (state.getValue(STAGE) == 0) { + worldIn.setBlockState(pos, state.cycleProperty(STAGE), 4); + } else { + this.grow(worldIn, rand, pos, state); + } } } } @@ -59,17 +69,14 @@ public IBlockState getStateFromMeta(int meta) { } @Override - public int getMetaFromState(IBlockState state) { - int i = 0; - i |= state.getValue(STAGE) << 3; - return i; + public int getMetaFromState(@NotNull IBlockState state) { + return state.getValue(STAGE) << 3; } - @NotNull @Override @SuppressWarnings("deprecation") - public AxisAlignedBB getBoundingBox(@NotNull IBlockState state, @NotNull IBlockAccess source, - @NotNull BlockPos pos) { + public @NotNull AxisAlignedBB getBoundingBox(@NotNull IBlockState state, @NotNull IBlockAccess source, + @NotNull BlockPos pos) { return SAPLING_AABB; } @@ -93,12 +100,18 @@ public boolean canBeReplacedByLeaves(@NotNull IBlockState state, @NotNull IBlock @Override public void grow(@NotNull World worldIn, @NotNull Random rand, @NotNull BlockPos pos, @NotNull IBlockState state) { - WorldGenRubberTree.TREE_GROW_INSTANCE.grow(worldIn, pos, rand); + if (!TerrainGen.saplingGrowTree(worldIn, rand, pos)) { + return; + } + + worldIn.setBlockState(pos, Blocks.AIR.getDefaultState(), 4); + if (!WorldGenRubberTree.INSTANCE_NOTIFY.generate(worldIn, rand, pos)) { + worldIn.setBlockState(pos, state, 4); + } } @Override - @NotNull - public EnumPlantType getPlantType(@NotNull IBlockAccess world, @NotNull BlockPos pos) { + public @NotNull EnumPlantType getPlantType(@NotNull IBlockAccess world, @NotNull BlockPos pos) { return EnumPlantType.Plains; } } diff --git a/src/main/java/gregtech/common/worldgen/WorldGenRubberTree.java b/src/main/java/gregtech/common/worldgen/WorldGenRubberTree.java deleted file mode 100644 index 910286f418c..00000000000 --- a/src/main/java/gregtech/common/worldgen/WorldGenRubberTree.java +++ /dev/null @@ -1,107 +0,0 @@ -package gregtech.common.worldgen; - -import gregtech.common.blocks.MetaBlocks; - -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import net.minecraft.world.gen.feature.WorldGenerator; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.terraingen.SaplingGrowTreeEvent; -import net.minecraftforge.fml.common.eventhandler.Event; - -import org.jetbrains.annotations.NotNull; - -import java.util.Random; - -import static gregtech.common.blocks.wood.BlockRubberLog.NATURAL; - -public class WorldGenRubberTree extends WorldGenerator { - - public static final WorldGenRubberTree TREE_GROW_INSTANCE = new WorldGenRubberTree(true); - public static final WorldGenRubberTree WORLD_GEN_INSTANCE = new WorldGenRubberTree(false); - - protected WorldGenRubberTree(boolean notify) { - super(notify); - } - - @Override - public boolean generate(@NotNull World world, @NotNull Random random, @NotNull BlockPos pos) { - return generateImpl(world, random, new BlockPos.MutableBlockPos(pos)); - } - - public boolean generateImpl(@NotNull World world, @NotNull Random random, BlockPos.MutableBlockPos pos) { - pos.setPos(pos.getX() + 8, world.getHeight() - 1, pos.getZ() + 8); - while (pos.getY() > 0 && world.isAirBlock(pos)) { - pos.setY(pos.getY() - 1); - } - pos.setY(pos.getY() + 1); - return grow(world, pos, random); - } - - public boolean grow(World world, BlockPos pos, Random random) { - if (world == null) { - return false; - } - SaplingGrowTreeEvent event = new SaplingGrowTreeEvent(world, random, pos); - MinecraftForge.TERRAIN_GEN_BUS.post(event); - if (event.getResult() == Event.Result.DENY) { - return false; - } - IBlockState woodBlock = MetaBlocks.RUBBER_LOG.getDefaultState().withProperty(NATURAL, true); - IBlockState leaves = MetaBlocks.RUBBER_LEAVES.getDefaultState(); - int height = getGrowHeight(world, pos); - if (height < 2) - return false; - height -= random.nextInt(height / 2 + 1); - height = Math.max(5, height); - BlockPos.MutableBlockPos tmpPos = new BlockPos.MutableBlockPos(); - for (int cHeight = 0; cHeight < height; cHeight++) { - BlockPos cPos = pos.up(cHeight); - setBlockAndNotifyAdequately(world, cPos, woodBlock); - if ((height < 7 && cHeight > 1) || cHeight > 2) { - for (int cx = pos.getX() - 2; cx <= pos.getX() + 2; cx++) { - for (int cz = pos.getZ() - 2; cz <= pos.getZ() + 2; cz++) { - int chance = Math.max(1, cHeight + 4 - height); - int dx = Math.abs(cx - pos.getX()); - int dz = Math.abs(cz - pos.getZ()); - if ((dx <= 1 && dz <= 1) || (dx <= 1 && random - .nextInt(chance) == 0) || (dz <= 1 && - random - .nextInt(chance) == 0)) { - tmpPos.setPos(cx, pos.getY() + cHeight, cz); - if (world.isAirBlock(tmpPos)) { - setBlockAndNotifyAdequately(world, new BlockPos(tmpPos), leaves); - } - } - } - } - } - } - for (int i = 0; i <= height / 4 + random.nextInt(2); i++) { - tmpPos.setPos(pos.getX(), pos.getY() + height + i, pos.getZ()); - if (world.isAirBlock(tmpPos)) - setBlockAndNotifyAdequately(world, new BlockPos(tmpPos), leaves); - } - return true; - } - - public int getGrowHeight(@NotNull World world, @NotNull BlockPos pos) { - BlockPos below = pos.down(); - IBlockState baseState = world.getBlockState(below); - Block baseBlock = baseState.getBlock(); - if (baseBlock.isAir(baseState, world, below) || - !baseBlock.canSustainPlant(baseState, world, below, EnumFacing.UP, MetaBlocks.RUBBER_SAPLING) || - (!world.isAirBlock(pos.up()) && world.getBlockState(pos.up()).getBlock() != MetaBlocks.RUBBER_SAPLING)) - return 0; - int height = 1; - pos = pos.up(); - while (world.isAirBlock(pos) && height < 7) { - pos = pos.up(); - height++; - } - return height; - } -} diff --git a/src/main/java/gregtech/worldgen/WorldgenModule.java b/src/main/java/gregtech/worldgen/WorldgenModule.java index c279c21e6eb..980d25f7b9d 100644 --- a/src/main/java/gregtech/worldgen/WorldgenModule.java +++ b/src/main/java/gregtech/worldgen/WorldgenModule.java @@ -5,7 +5,14 @@ import gregtech.common.ConfigHolder; import gregtech.modules.BaseGregTechModule; import gregtech.modules.GregTechModules; +import gregtech.worldgen.impl.WorldGenRubberTree; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraftforge.common.BiomeDictionary; +import net.minecraftforge.event.terraingen.DecorateBiomeEvent; import net.minecraftforge.event.terraingen.OreGenEvent; import net.minecraftforge.fml.common.eventhandler.Event; import net.minecraftforge.fml.common.eventhandler.EventPriority; @@ -18,6 +25,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.List; +import java.util.Random; import java.util.Set; import static net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.*; @@ -39,6 +47,11 @@ public class WorldgenModule extends BaseGregTechModule { return LOGGER; } + @Override + public @NotNull List> getTerrainGenBusSubscribers() { + return Collections.singletonList(WorldgenModule.class); + } + @Override public @NotNull List> getOreGenBusSubscribers() { return Collections.singletonList(WorldgenModule.class); @@ -50,4 +63,66 @@ public static void onGenerateMineable(@NotNull OreGenEvent.GenerateMinable event event.setResult(Event.Result.DENY); } } + + @SubscribeEvent + public static void onBiomeDecorate(@NotNull DecorateBiomeEvent.Decorate event) { + if (event.getType() == DecorateBiomeEvent.Decorate.EventType.TREE) { + if (ConfigHolder.worldgen.disableRubberTreeGeneration) { + return; + } + + // replaces regular tree generation with occasional rubber trees + if (generateRubberTrees(event.getWorld(), event.getChunkPos(), event.getRand())) { + event.setResult(Event.Result.DENY); + } + } + } + + /** + * Generates a rubber trees + * + * @param world the world in which the tree should be placed + * @param chunkPos the position of the chunk the tree should be generated at + * @param random the random number generator to use + * @return if trees were generated + */ + private static boolean generateRubberTrees(@NotNull World world, @NotNull ChunkPos chunkPos, + @NotNull Random random) { + BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); + + final int chunkX = chunkPos.x * 16; + final int chunkZ = chunkPos.z * 16; + pos.setPos(chunkX + 16, 0, chunkZ + 16); + Biome biome = world.getBiome(pos); + + int amount = 0; + if (BiomeDictionary.hasType(biome, BiomeDictionary.Type.SWAMP)) { + amount += random.nextInt(10) + 5; + } + if (BiomeDictionary.hasType(biome, BiomeDictionary.Type.FOREST) || + BiomeDictionary.hasType(biome, BiomeDictionary.Type.JUNGLE)) { + amount += random.nextInt(5) + 1; + } + + amount = (int) (amount * ConfigHolder.worldgen.rubberTreeRateIncrease / 2); + if (amount > 0 && random.nextInt(100) < amount) { + boolean generated = false; + for (int i = 0; i < amount; i++) { + int x = chunkX + random.nextInt(16) + 8; + int z = chunkZ + random.nextInt(16) + 8; + int y = world.getHeight(x, z); + pos.setPos(x, y, z); + + WorldGenRubberTree.INSTANCE.setDecorationDefaults(); + if (WorldGenRubberTree.INSTANCE.generate(world, random, pos)) { + WorldGenRubberTree.INSTANCE.generateSaplings(world, random, pos); + generated = true; + } + } + + return generated; + } + + return false; + } } diff --git a/src/main/java/gregtech/worldgen/impl/WorldGenRubberTree.java b/src/main/java/gregtech/worldgen/impl/WorldGenRubberTree.java new file mode 100644 index 00000000000..9cf257a62c3 --- /dev/null +++ b/src/main/java/gregtech/worldgen/impl/WorldGenRubberTree.java @@ -0,0 +1,126 @@ +package gregtech.worldgen.impl; + +import gregtech.common.blocks.MetaBlocks; +import gregtech.common.blocks.wood.BlockRubberLog; + +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenAbstractTree; + +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +public class WorldGenRubberTree extends WorldGenAbstractTree { + + public static final WorldGenRubberTree INSTANCE = new WorldGenRubberTree(false); + public static final WorldGenRubberTree INSTANCE_NOTIFY = new WorldGenRubberTree(true); + + protected WorldGenRubberTree(boolean notify) { + super(notify); + } + + @Override + public boolean generate(@NotNull World world, @NotNull Random rand, @NotNull BlockPos pos) { + int trunkHeight = rand.nextInt(3) + 5; // 5-7 logs + + final int maxWorldHeight = world.getHeight(); + int posX = pos.getX(); + int posY = pos.getY(); + int posZ = pos.getZ(); + + if (posY <= 1) { + return false; + } + + final int topLeafHeight = trunkHeight + 3; + final int ySpaceRequired = posY + topLeafHeight + 1; + final int leafStartY = ySpaceRequired - 2; + + // check if there is enough room to fit the whole tree + if (ySpaceRequired >= maxWorldHeight) { + return false; + } + BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); + for (int y = posY; y < ySpaceRequired; y++) { + int radius; + if (y == posY) { + radius = 0; + } else if (y < leafStartY) { + radius = 1; + } else { + radius = 2; + } + + final int xLimit = posX + radius; + final int zLimit = posZ + radius; + for (int x = posX - radius; x <= xLimit; x++) { + for (int z = posZ - radius; z < zLimit; z++) { + mutable.setPos(x, y, z); + if (!isReplaceable(world, mutable)) { + return false; + } + } + } + } + + // check for valid soil + mutable.setPos(posX, posY - 1, posZ); + IBlockState soilState = world.getBlockState(mutable); + Block soilBlock = soilState.getBlock(); + if (!soilBlock.canSustainPlant(soilState, world, mutable, EnumFacing.UP, MetaBlocks.RUBBER_SAPLING)) { + return false; + } + + soilBlock.onPlantGrow(soilState, world, mutable, pos); + + // leaves + final int leavesOnTrunk = 4; + final int slimmingPoint = trunkHeight - 2; + int leafRadius = 2; + for (int yOffset = trunkHeight - leavesOnTrunk; yOffset < topLeafHeight; yOffset++) { + if (yOffset == slimmingPoint) { + leafRadius = 1; + } else if (yOffset == trunkHeight) { + leafRadius = 0; + } + + int y = posY + yOffset; + for (int xOffset = -leafRadius; xOffset <= leafRadius; xOffset++) { + int x = posX + xOffset; + for (int zOffset = -leafRadius; zOffset <= leafRadius; zOffset++) { + int z = posZ + zOffset; + if (y <= trunkHeight && xOffset == 0 && zOffset == 0) { + // skip the trunk + continue; + } + if (leafRadius == 0 || Math.abs(xOffset) < leafRadius || Math.abs(zOffset) < leafRadius || + (yOffset <= slimmingPoint && rand.nextBoolean())) { + mutable.setPos(x, y, z); + IBlockState existing = world.getBlockState(mutable); + if (existing.getBlock().isAir(existing, world, mutable)) { + setBlockAndNotifyAdequately(world, mutable, MetaBlocks.RUBBER_LEAVES.getDefaultState()); + } + } + } + } + } + + // trunk + IBlockState logState = MetaBlocks.RUBBER_LOG.getDefaultState().withProperty(BlockRubberLog.NATURAL, true); + mutable.setPos(posX, posY, posZ); + for (int y = 0; y < trunkHeight; y++) { + mutable.setY(posY + y); + IBlockState existing = world.getBlockState(mutable); + if (existing.getBlock().isAir(existing, world, mutable) || + existing.getBlock().isLeaves(existing, world, mutable)) { + setBlockAndNotifyAdequately(world, mutable, logState); + } + } + + return true; + } +}