From bc89e7ebb9e516559f9fa39b2f63652802781abd Mon Sep 17 00:00:00 2001 From: dags- Date: Sat, 20 Jun 2020 14:42:23 +0100 Subject: [PATCH] add custom bush feature for scrub-type biomes --- Engine | 2 +- FeatureManager | 2 +- .../java/com/terraforged/TerraForgedMod.java | 2 + .../feature/feature/BushFeature.java | 139 ++++++++++++++++++ .../feature/feature/FreezeLayer.java | 20 ++- .../features/shrubs/cold_steppe_bush.json | 44 ++++++ .../features/shrubs/steppe_bush.json | 46 ++++++ .../features/shrubs/taiga_scrub_bush.json | 44 ++++++ 8 files changed, 291 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/terraforged/feature/feature/BushFeature.java create mode 100644 src/main/resources/data/terraforged/features/shrubs/cold_steppe_bush.json create mode 100644 src/main/resources/data/terraforged/features/shrubs/steppe_bush.json create mode 100644 src/main/resources/data/terraforged/features/shrubs/taiga_scrub_bush.json diff --git a/Engine b/Engine index 74305c7..78d4984 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit 74305c79ee507602f7721478fbd5029bb5a9a51b +Subproject commit 78d4984ce66912d7844cffb8b7fa69dfc1630f24 diff --git a/FeatureManager b/FeatureManager index 11ec92c..95307b3 160000 --- a/FeatureManager +++ b/FeatureManager @@ -1 +1 @@ -Subproject commit 11ec92c8c103ddd1a30edcf0376f6270320e37d8 +Subproject commit 95307b3315188255f7a57691500b8ec05a8b75e2 diff --git a/src/main/java/com/terraforged/TerraForgedMod.java b/src/main/java/com/terraforged/TerraForgedMod.java index 31262ea..8c5fede 100644 --- a/src/main/java/com/terraforged/TerraForgedMod.java +++ b/src/main/java/com/terraforged/TerraForgedMod.java @@ -31,6 +31,7 @@ import com.terraforged.config.ConfigManager; import com.terraforged.data.DataGen; import com.terraforged.feature.context.ContextSelectorFeature; import com.terraforged.feature.decorator.poisson.PoissonAtSurface; +import com.terraforged.feature.feature.BushFeature; import com.terraforged.feature.feature.DiskFeature; import com.terraforged.feature.feature.FreezeLayer; import com.terraforged.fm.template.TemplateManager; @@ -87,6 +88,7 @@ public class TerraForgedMod { TemplateManager.register(event); event.getRegistry().register(DiskFeature.INSTANCE); event.getRegistry().register(FreezeLayer.INSTANCE); + event.getRegistry().register(BushFeature.INSTANCE); event.getRegistry().register(ContextSelectorFeature.INSTANCE); } diff --git a/src/main/java/com/terraforged/feature/feature/BushFeature.java b/src/main/java/com/terraforged/feature/feature/BushFeature.java new file mode 100644 index 0000000..6d70b7a --- /dev/null +++ b/src/main/java/com/terraforged/feature/feature/BushFeature.java @@ -0,0 +1,139 @@ +package com.terraforged.feature.feature; + +import com.google.common.collect.ImmutableMap; +import com.mojang.datafixers.Dynamic; +import com.mojang.datafixers.types.DynamicOps; +import com.terraforged.fm.template.BlockUtils; +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3i; +import net.minecraft.world.IWorld; +import net.minecraft.world.gen.ChunkGenerator; +import net.minecraft.world.gen.GenerationSettings; +import net.minecraft.world.gen.Heightmap; +import net.minecraft.world.gen.feature.Feature; +import net.minecraft.world.gen.feature.IFeatureConfig; + +import java.util.Random; + +public class BushFeature extends Feature { + + public static final BushFeature INSTANCE = new BushFeature(); + + private static final Vec3i[] logs = { + new Vec3i(+1, 0, +1), + new Vec3i(+1, 0, -1), + new Vec3i(-1, 0, -1), + new Vec3i(-1, 0, +1), + + new Vec3i(+2, 0, +1), + new Vec3i(+2, 0, -1), + new Vec3i(-2, 0, +1), + new Vec3i(-2, 0, -1), + + new Vec3i(+1, 0, +2), + new Vec3i(+1, 0, -2), + new Vec3i(-1, 0, +2), + new Vec3i(-1, 0, -2), + }; + + private static final Vec3i[] leaves = { + new Vec3i(0, 0, 1), + new Vec3i(0, 0, -1), + new Vec3i(1, 0, 0), + new Vec3i(-1, 0, 0), + new Vec3i(0, 1, 0), + }; + + public BushFeature() { + super(BushFeature::deserialize); + setRegistryName("terraforged", "bush"); + } + + @Override + public boolean place(IWorld world, ChunkGenerator generator, Random rand, BlockPos pos, Config config) { + try (BlockPos.PooledMutable log = BlockPos.PooledMutable.retain(); BlockPos.PooledMutable leaf = BlockPos.PooledMutable.retain()) { + place(world, log.setPos(pos), leaf, rand, config); + for (float chance = rand.nextFloat(); chance < config.size_chance; chance += rand.nextFloat()) { + add(log, logs[rand.nextInt(logs.length)]); + + if (!place(world, log, leaf, rand, config)) { + break; + } + } + } + return true; + } + + private boolean place(IWorld world, BlockPos.Mutable center, BlockPos.Mutable pos, Random random, Config config) { + int y = world.getHeight(Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, center.getX(), center.getZ()); + + center.setY(y); + world.setBlockState(center, config.trunk, 2); + + for (Vec3i neighbour : leaves) { + if (neighbour.getY() == 0 && random.nextFloat() < config.airChance) { + continue; + } + + pos.setPos(center); + add(pos, neighbour); + + if (!BlockUtils.isSolid(world, pos)) { + world.setBlockState(pos, config.leaves, 2); + + if (neighbour.getY() == 0 && random.nextFloat() < config.leafChance) { + pos.move(Direction.UP, 1); + world.setBlockState(pos, config.leaves, 2); + } + } + } + + return true; + } + + private static void add(BlockPos.Mutable pos, Vec3i add) { + pos.setPos(pos.getX() + add.getX(), pos.getY() + add.getY(), pos.getZ() + add.getZ()); + } + + public static Config deserialize(Dynamic data) { + BlockState logs = BlockState.deserialize(data.get("trunk").get().get()); + BlockState leaves = BlockState.deserialize(data.get("leaves").get().get()); + float airChance = data.get("air_chance").asFloat(0.075F); + float leafChance = data.get("leaf_chance").asFloat(0.075F); + float sizeChance = data.get("size_chance").asFloat(0.75F); + return new Config(logs, leaves, airChance, leafChance, sizeChance); + } + + public static class Config implements IFeatureConfig { + + private final BlockState trunk; + private final BlockState leaves; + private final float airChance; + private final float leafChance; + private final float size_chance; + + public Config(BlockState trunk, BlockState leaves, float airChance, float leafChance, float size_chance) { + this.trunk = trunk; + this.leaves = leaves; + this.airChance = airChance; + this.leafChance = leafChance; + this.size_chance = size_chance; + } + + @Override + public Dynamic serialize(DynamicOps ops) { + return new Dynamic<>( + ops, + ops.createMap(ImmutableMap.of( + ops.createString("trunk"), BlockState.serialize(ops, trunk).getValue(), + ops.createString("leaves"), BlockState.serialize(ops, leaves).getValue(), + ops.createString("air_chance"), ops.createFloat(airChance), + ops.createString("leaf_chance"), ops.createFloat(airChance), + ops.createString("size_chance"), ops.createFloat(size_chance) + )) + ); + } + } +} diff --git a/src/main/java/com/terraforged/feature/feature/FreezeLayer.java b/src/main/java/com/terraforged/feature/feature/FreezeLayer.java index 946f988..d0b5066 100644 --- a/src/main/java/com/terraforged/feature/feature/FreezeLayer.java +++ b/src/main/java/com/terraforged/feature/feature/FreezeLayer.java @@ -1,5 +1,6 @@ package com.terraforged.feature.feature; +import com.terraforged.fm.template.BlockUtils; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.SnowyDirtBlock; @@ -73,15 +74,17 @@ public class FreezeLayer extends Feature { return false; } - BlockState above = world.getBlockState(top.up()); + top.move(Direction.UP, 1); + BlockState above = world.getBlockState(top); if (BlockTags.LOGS.contains(above.getBlock()) || BlockTags.LEAVES.contains(above.getBlock())) { return false; } - setSnow(world, top, below, stateUnder); - - if (above.getBlock() != Blocks.AIR) { - world.setBlockState(top, Blocks.AIR.getDefaultState(), 2); + top.move(Direction.DOWN, 1); + if (setSnow(world, top, below, stateUnder)) { + if (above.getBlock() != Blocks.AIR) { + world.setBlockState(top, Blocks.AIR.getDefaultState(), 2); + } } } else { setSnow(world, top, below, stateUnder); @@ -90,11 +93,16 @@ public class FreezeLayer extends Feature { return hasFrozen; } - private void setSnow(IWorld world, BlockPos pos1, BlockPos pos2, BlockState below) { + private boolean setSnow(IWorld world, BlockPos pos1, BlockPos pos2, BlockState below) { + if (BlockUtils.isSolid(world, pos1)) { + return false; + } + world.setBlockState(pos1, Blocks.SNOW.getDefaultState(), 2); if (below.has(SnowyDirtBlock.SNOWY)) { world.setBlockState(pos2, below.with(SnowyDirtBlock.SNOWY, true), 2); } + return true; } } diff --git a/src/main/resources/data/terraforged/features/shrubs/cold_steppe_bush.json b/src/main/resources/data/terraforged/features/shrubs/cold_steppe_bush.json new file mode 100644 index 0000000..026f2c4 --- /dev/null +++ b/src/main/resources/data/terraforged/features/shrubs/cold_steppe_bush.json @@ -0,0 +1,44 @@ +{ + "biomes": [ + "terraforged:cold_steppe" + ], + "match": [ + [ + "minecraft:grass" + ] + ], + "before": { + "name": "minecraft:decorated", + "config": { + "feature": { + "name": "terraforged:bush", + "config": { + "trunk": { + "Name": "minecraft:spruce_log", + "Properties": { + "axis": "y" + } + }, + "leaves": { + "Name": "minecraft:spruce_leaves", + "Properties": { + "distance": "7", + "persistent": "false" + } + }, + "air_chance": 0.05, + "leaf_chance": 0.075, + "size_chance": 0.6 + } + }, + "decorator": { + "name": "minecraft:count_extra_heightmap", + "config": { + "count": 0, + "extra_chance": 0.2, + "extra_count": 1 + } + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/data/terraforged/features/shrubs/steppe_bush.json b/src/main/resources/data/terraforged/features/shrubs/steppe_bush.json new file mode 100644 index 0000000..33b2dc7 --- /dev/null +++ b/src/main/resources/data/terraforged/features/shrubs/steppe_bush.json @@ -0,0 +1,46 @@ +{ + "biomes": [ + "terraforged:steppe", + "terraforged:savanna_scrub", + "terraforged:shattered_savanna_scrub" + ], + "match": [ + [ + "minecraft:grass" + ] + ], + "before": { + "name": "minecraft:decorated", + "config": { + "feature": { + "name": "terraforged:bush", + "config": { + "trunk": { + "Name": "minecraft:acacia_log", + "Properties": { + "axis": "y" + } + }, + "leaves": { + "Name": "minecraft:acacia_leaves", + "Properties": { + "distance": "7", + "persistent": "false" + } + }, + "air_chance": 0.06, + "leaf_chance": 0.08, + "size_chance": 0.7 + } + }, + "decorator": { + "name": "minecraft:count_extra_heightmap", + "config": { + "count": 0, + "extra_chance": 0.12, + "extra_count": 1 + } + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/data/terraforged/features/shrubs/taiga_scrub_bush.json b/src/main/resources/data/terraforged/features/shrubs/taiga_scrub_bush.json new file mode 100644 index 0000000..7b2da8e --- /dev/null +++ b/src/main/resources/data/terraforged/features/shrubs/taiga_scrub_bush.json @@ -0,0 +1,44 @@ +{ + "biomes": [ + "terraforged:taiga_scrub" + ], + "match": [ + [ + "minecraft:grass" + ] + ], + "before": { + "name": "minecraft:decorated", + "config": { + "feature": { + "name": "terraforged:bush", + "config": { + "trunk": { + "Name": "minecraft:spruce_log", + "Properties": { + "axis": "y" + } + }, + "leaves": { + "Name": "minecraft:spruce_leaves", + "Properties": { + "distance": "7", + "persistent": "false" + } + }, + "air_chance": 0.05, + "leaf_chance": 0.075, + "size_chance": 0.6 + } + }, + "decorator": { + "name": "minecraft:count_extra_heightmap", + "config": { + "count": 0, + "extra_chance": 0.1, + "extra_count": 1 + } + } + } + } +} \ No newline at end of file