somewhat fancy tree generation

This commit is contained in:
Halbear
2026-07-23 03:32:20 +01:00
parent ec63c2540f
commit 0dcf2b4a47
16 changed files with 627 additions and 18 deletions
@@ -0,0 +1,6 @@
{
"type": "neoforge:add_features",
"biomes": "ageofthegods:maquis_shrubland",
"features": "ageofthegods:twisty_tree_placed",
"step": "vegetal_decoration"
}
@@ -0,0 +1,64 @@
{
"type": "minecraft:tree",
"config": {
"below_trunk_provider": {
"type": "minecraft:rule_based_state_provider",
"rules": [
{
"if_true": {
"type": "minecraft:not",
"predicate": {
"type": "minecraft:matching_block_tag",
"tag": "minecraft:cannot_replace_below_tree_trunk"
}
},
"then": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:dirt"
}
}
}
]
},
"decorators": [],
"foliage_placer": {
"type": "ageofthegods:spherical_foliage_placer",
"offset": 0,
"radius": 1
},
"foliage_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_leaves",
"Properties": {
"distance": "7",
"persistent": "false",
"waterlogged": "false"
}
}
},
"ignore_vines": false,
"minimum_size": {
"type": "minecraft:two_layers_feature_size",
"limit": 5,
"lower_size": 3,
"upper_size": 5
},
"trunk_placer": {
"type": "ageofthegods:twisty_trunk_placer",
"base_height": 10,
"height_rand_a": 6,
"height_rand_b": 4
},
"trunk_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_log",
"Properties": {
"axis": "y"
}
}
}
}
}
@@ -0,0 +1,44 @@
{
"feature": "ageofthegods:twisty_tree",
"placement": [
{
"type": "minecraft:count",
"count": 10
},
{
"type": "minecraft:rarity_filter",
"chance": 10
},
{
"type": "minecraft:in_square"
},
{
"type": "minecraft:heightmap",
"heightmap": "OCEAN_FLOOR"
},
{
"type": "minecraft:block_predicate_filter",
"predicate": {
"type": "minecraft:matching_blocks",
"blocks": [
"ageofthegods:shale_grass_block",
"minecraft:sandstone",
"ageofthegods:shale_block",
"ageofthegods:limestone_grass_block"
],
"offset": [
0,
-1,
0
]
}
},
{
"type": "minecraft:surface_water_depth_filter",
"max_water_depth": 0
},
{
"type": "minecraft:biome"
}
]
}
@@ -488,10 +488,19 @@
"secondary_depth_range": 0, "secondary_depth_range": 0,
"surface_type": "floor" "surface_type": "floor"
}, },
"then_run": {
"type": "minecraft:condition",
"if_true": {
"type": "minecraft:noise_threshold",
"max_threshold": 1.7976931348623157E308,
"min_threshold": 0.0,
"noise": "ageofthegods:tiny_patchy_noise"
},
"then_run": { "then_run": {
"type": "minecraft:block", "type": "minecraft:block",
"result_state": { "result_state": {
"Name": "ageofthegods:limestone_block" "Name": "ageofthegods:limestone_grass_block"
}
} }
} }
}, },
@@ -500,7 +509,23 @@
"if_true": { "if_true": {
"type": "minecraft:stone_depth", "type": "minecraft:stone_depth",
"add_surface_depth": false, "add_surface_depth": false,
"offset": 4, "offset": 0,
"secondary_depth_range": 0,
"surface_type": "floor"
},
"then_run": {
"type": "minecraft:block",
"result_state": {
"Name": "minecraft:sandstone"
}
}
},
{
"type": "minecraft:condition",
"if_true": {
"type": "minecraft:stone_depth",
"add_surface_depth": false,
"offset": 10,
"secondary_depth_range": 0, "secondary_depth_range": 0,
"surface_type": "floor" "surface_type": "floor"
}, },
@@ -550,6 +575,31 @@
} }
} }
}, },
{
"type": "minecraft:condition",
"if_true": {
"type": "minecraft:stone_depth",
"add_surface_depth": false,
"offset": 0,
"secondary_depth_range": 0,
"surface_type": "floor"
},
"then_run": {
"type": "minecraft:condition",
"if_true": {
"type": "minecraft:noise_threshold",
"max_threshold": 1.7976931348623157E308,
"min_threshold": 0.1,
"noise": "ageofthegods:tiny_patchy_noise"
},
"then_run": {
"type": "minecraft:block",
"result_state": {
"Name": "minecraft:granite"
}
}
}
},
{ {
"type": "minecraft:condition", "type": "minecraft:condition",
"if_true": { "if_true": {
@@ -571,7 +621,32 @@
"if_true": { "if_true": {
"type": "minecraft:stone_depth", "type": "minecraft:stone_depth",
"add_surface_depth": false, "add_surface_depth": false,
"offset": 4, "offset": 10,
"secondary_depth_range": 0,
"surface_type": "floor"
},
"then_run": {
"type": "minecraft:condition",
"if_true": {
"type": "minecraft:noise_threshold",
"max_threshold": 1.7976931348623157E308,
"min_threshold": 0.1,
"noise": "ageofthegods:tiny_patchy_noise"
},
"then_run": {
"type": "minecraft:block",
"result_state": {
"Name": "minecraft:granite"
}
}
}
},
{
"type": "minecraft:condition",
"if_true": {
"type": "minecraft:stone_depth",
"add_surface_depth": false,
"offset": 10,
"secondary_depth_range": 0, "secondary_depth_range": 0,
"surface_type": "floor" "surface_type": "floor"
}, },
@@ -39,7 +39,9 @@ import net.neoforged.neoforge.registries.DeferredItem;
import net.neoforged.neoforge.registries.DeferredRegister; import net.neoforged.neoforge.registries.DeferredRegister;
import static net.halbear.aotg.registries.ModBlocks.*; import static net.halbear.aotg.registries.ModBlocks.*;
import static net.halbear.aotg.registries.ModFoliagePlacers.FOLIAGE_PLACERS;
import static net.halbear.aotg.registries.ModItems.*; import static net.halbear.aotg.registries.ModItems.*;
import static net.halbear.aotg.registries.ModTreeGen.TRUNK_PLACERS;
// The value here should match an entry in the META-INF/neoforge.mods.toml file // The value here should match an entry in the META-INF/neoforge.mods.toml file
@Mod(AgeoftheGods.MODID) @Mod(AgeoftheGods.MODID)
@@ -74,6 +76,10 @@ public class AgeoftheGods {
ITEMS.register(modEventBus); ITEMS.register(modEventBus);
// Register the Deferred Register to the mod event bus so tabs get registered // Register the Deferred Register to the mod event bus so tabs get registered
CREATIVE_MODE_TABS.register(modEventBus); CREATIVE_MODE_TABS.register(modEventBus);
TRUNK_PLACERS.register(modEventBus);
FOLIAGE_PLACERS.register(modEventBus);
// Register ourselves for server and other game events we are interested in. // Register ourselves for server and other game events we are interested in.
// Note that this is necessary if and only if we want *this* class (AgeoftheGods) to respond directly to events. // Note that this is necessary if and only if we want *this* class (AgeoftheGods) to respond directly to events.
// Do not add this line if there are no @SubscribeEvent-annotated functions in this class, like onServerStarting() below. // Do not add this line if there are no @SubscribeEvent-annotated functions in this class, like onServerStarting() below.
@@ -0,0 +1,57 @@
package net.halbear.aotg.custom.WorldGen.GenerationFeatures;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.halbear.aotg.registries.ModFoliagePlacers;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.util.valueproviders.IntProvider;
import net.minecraft.world.level.LevelSimulatedReader;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration;
import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacer;
import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacerType;
public class LeafBunchFoliagePlacer extends FoliagePlacer {
public static final MapCodec<LeafBunchFoliagePlacer> CODEC = RecordCodecBuilder.mapCodec(instance ->
foliagePlacerParts(instance).apply(instance, LeafBunchFoliagePlacer::new)
);
public LeafBunchFoliagePlacer(IntProvider radius, IntProvider offset) {
super(radius, offset);
}
@Override
protected FoliagePlacerType<?> type() {
return ModFoliagePlacers.LEAF_BUNCH_FOLIAGE_PLACER.get();
}
@Override
protected void createFoliage(WorldGenLevel worldGenLevel, FoliageSetter foliageSetter, RandomSource randomSource, TreeConfiguration treeConfiguration, int i, FoliageAttachment foliageAttachment, int foliageHeight, int radius, int offset) {
BlockPos center = foliageAttachment.pos().above(offset);
radius += foliageAttachment.radiusOffset();
double radiusSq = radius * radius;
for (int x = -radius; x <= radius; x++) {
for (int y = -radius; y <= radius; y++) {
for (int z = -radius; z <= radius; z++) {
double distanceSq = (x * x) + (y * y) + (z * z);
if (distanceSq <= radiusSq + 0.5 && randomSource.nextDouble() < 0.6) {
tryPlaceLeaf(worldGenLevel, foliageSetter, randomSource, treeConfiguration, center.offset(x, y, z));
}
}
}
}
}
@Override
public int foliageHeight(RandomSource random, int height, TreeConfiguration config) {
return 0;
}
@Override
protected boolean shouldSkipLocation(RandomSource random, int localX, int localY, int localZ, int range, boolean large) {
return false;
}
}
@@ -0,0 +1,143 @@
package net.halbear.aotg.custom.WorldGen.GenerationFeatures;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.halbear.aotg.registries.ModTreeGen;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.LevelSimulatedReader;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration;
import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacer;
import net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacer;
import net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacerType;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
public class TwistyBranchingTrunkPlacer extends TrunkPlacer {
private static final int BEGINNING_TRUNK_WIDTH = 5;
public TwistyBranchingTrunkPlacer(int baseHeight, int heightRandA, int heightRandB) {
super(baseHeight, heightRandA, heightRandB);
}
public static final MapCodec<TwistyBranchingTrunkPlacer> CODEC = RecordCodecBuilder.mapCodec(instance ->
trunkPlacerParts(instance).apply(instance, TwistyBranchingTrunkPlacer::new)
);
@Override
protected TrunkPlacerType<?> type() {
return ModTreeGen.TWISTY_TRUNK_PLACER.get();
}
@Override
public List<FoliagePlacer.FoliageAttachment> placeTrunk(WorldGenLevel worldGenLevel, BiConsumer<BlockPos, BlockState> biConsumer, RandomSource randomSource, int freeSpace, BlockPos blockPos, TreeConfiguration treeConfiguration) {
int TRUNK_WIDTH = BEGINNING_TRUNK_WIDTH;
List<FoliagePlacer.FoliageAttachment> leafNodes = new ArrayList<>();
int mainHeight = this.getTreeHeight(randomSource);
BlockPos currentPos = blockPos;
for (int i = 0; i < mainHeight; i++) {
TRUNK_WIDTH = (int)Math.max(BEGINNING_TRUNK_WIDTH * (1.0-((i*0.75)/(double)mainHeight)),2);
for (int xOffset = 0; xOffset < TRUNK_WIDTH; xOffset++) {
for (int zOffset = 0; zOffset < TRUNK_WIDTH; zOffset++) {
BlockPos thickLogPos = currentPos.offset(xOffset, 0, zOffset);
if(i == 0 ) {
if (checkPointPosition(xOffset, zOffset, TRUNK_WIDTH / 2.0, TRUNK_WIDTH / 2.0, TRUNK_WIDTH / 2.0) != 1 && (randomSource.nextInt(10) < 9) || TRUNK_WIDTH < 3)
this.placeLog(worldGenLevel, biConsumer, randomSource, thickLogPos.below(), treeConfiguration);
}
if(i < 2 && randomSource.nextFloat() < 0.40f){
generateRoots(worldGenLevel, biConsumer, randomSource, thickLogPos, treeConfiguration);
}
if (checkPointPosition(xOffset, zOffset, TRUNK_WIDTH / 2.0, TRUNK_WIDTH / 2.0, TRUNK_WIDTH / 2.0) != 1 && (randomSource.nextInt(10) < 9) || TRUNK_WIDTH < 3)
this.placeLog(worldGenLevel, biConsumer, randomSource, thickLogPos, treeConfiguration);
else if (randomSource.nextDouble() < 0.1)
leafNodes.add(new FoliagePlacer.FoliageAttachment(thickLogPos, randomSource.nextInt(2), false));
}
}
if (randomSource.nextFloat() < 0.6f && i > 1) {
currentPos = currentPos.offset(randomSource.nextInt(3) - 1, 0, randomSource.nextInt(3) - 1);
}
if (i > 2 && randomSource.nextFloat() < 0.40f) {
BlockPos branchStart = currentPos.offset(randomSource.nextInt(TRUNK_WIDTH), 0, randomSource.nextInt(TRUNK_WIDTH));
BlockPos branchEnd = generateBranch(worldGenLevel, biConsumer, randomSource, branchStart, treeConfiguration,i, leafNodes);
leafNodes.add(new FoliagePlacer.FoliageAttachment(branchEnd, randomSource.nextInt(2) + (Math.max((int)(i/(double)(mainHeight/1.25))*3,1)), false));
} else if(i > 2 && i == mainHeight - 1){
for(int l = 0; l < 1 + randomSource.nextInt(2); l++){
BlockPos branchStart = currentPos.offset(randomSource.nextInt(TRUNK_WIDTH), 0, randomSource.nextInt(TRUNK_WIDTH));
BlockPos branchEnd = generateBranch(worldGenLevel, biConsumer, randomSource, branchStart, treeConfiguration,i, leafNodes);
leafNodes.add(new FoliagePlacer.FoliageAttachment(branchEnd, randomSource.nextInt(2) + (Math.max((int)(i/(double)(mainHeight/1.25))*3,1)), false));
}
}
currentPos = currentPos.above();
}
for (int xOffset = 0; xOffset < TRUNK_WIDTH; xOffset++) {
for (int zOffset = 0; zOffset < TRUNK_WIDTH; zOffset++) {
leafNodes.add(new FoliagePlacer.FoliageAttachment(currentPos.offset(xOffset, 0, zOffset), 0, false));
}
}
return leafNodes;
}
private BlockPos generateRoots(WorldGenLevel level, BiConsumer<BlockPos, BlockState> blockSetter,
RandomSource random, BlockPos branchStart, TreeConfiguration config) {
int dirX = random.nextBoolean() ? 1 : -1;
int dirZ = random.nextBoolean() ? 1 : -1;
int branchLength = 2 + random.nextInt(6);
BlockPos bPos = branchStart;
for (int b = 0; b < branchLength; b++) {
int stepX = random.nextFloat() < 0.7f ? dirX : 0;
int stepZ = random.nextFloat() < 0.7f ? dirZ : 0;
int stepY = random.nextFloat() < 0.4f ? -1 : 0;
bPos = bPos.offset(stepX, stepY, stepZ);
this.placeLog(level, blockSetter, random, bPos, config);
}
return bPos;
}
private BlockPos generateBranch(WorldGenLevel level, BiConsumer<BlockPos, BlockState> blockSetter,
RandomSource random, BlockPos branchStart, TreeConfiguration config, int CurrentTreeHeight,List<FoliagePlacer.FoliageAttachment> leafNodes) {
int dirX = random.nextBoolean() ? 1 : -1;
int dirZ = random.nextBoolean() ? 1 : -1;
int branchLength = 3 + random.nextInt(Math.min(CurrentTreeHeight,12));
BlockPos bPos = branchStart;
for (int b = 0; b < branchLength; b++) {
int stepX = random.nextFloat() < 0.7f ? dirX : 0;
int stepZ = random.nextFloat() < 0.7f ? dirZ : 0;
int stepY = random.nextFloat() < 0.4f ? 1 : 0;
bPos = bPos.offset(stepX, stepY, stepZ);
this.placeLog(level, blockSetter, random, bPos, config);
if (random.nextDouble() < 0.25) {
leafNodes.add(new FoliagePlacer.FoliageAttachment(bPos, random.nextInt(2), false));
}
}
return bPos;
}
public static int checkPointPosition(double xp, double yp, double xc, double yc, double r) {
double dx = xp - xc;
double dy = yp - yc;
double squaredDistance = (dx * dx) + (dy * dy);
double squaredRadius = r * r * 1.25;
if (squaredDistance < squaredRadius) {
return -1;
} else if (squaredDistance == squaredRadius) {
return 0;
} else {
return 1;
}
}
}
@@ -25,11 +25,20 @@ public class ModNoiseSettings {
ResourceKey<net.minecraft.world.level.biome.Biome> maquisKey = ResourceKey<net.minecraft.world.level.biome.Biome> maquisKey =
ResourceKey.create(Registries.BIOME, Identifier.fromNamespaceAndPath(AgeoftheGods.MODID, "maquis_shrubland")); ResourceKey.create(Registries.BIOME, Identifier.fromNamespaceAndPath(AgeoftheGods.MODID, "maquis_shrubland"));
SurfaceRules.ConditionSource isGarrigueGrassPatch = SurfaceRules.noiseCondition(Noises.POWDER_SNOW, 0.0); SurfaceRules.ConditionSource isGarrigueGrassSection = SurfaceRules.noiseCondition(Noises.POWDER_SNOW, 0);
SurfaceRules.ConditionSource isGarrigueGrassPatch = SurfaceRules.noiseCondition(AgeOfTheGodsDataGeneration.TINY_PATCHY_NOISE, 0.0);
SurfaceRules.ConditionSource isMaquisGrassPatch = SurfaceRules.noiseCondition(AgeOfTheGodsDataGeneration.TINY_PATCHY_NOISE, 0.0); SurfaceRules.ConditionSource isMaquisGrassPatch = SurfaceRules.noiseCondition(AgeOfTheGodsDataGeneration.TINY_PATCHY_NOISE, 0.0);
SurfaceRules.ConditionSource isGranite = SurfaceRules.noiseCondition(AgeOfTheGodsDataGeneration.TINY_PATCHY_NOISE, 0.1);
SurfaceRules.RuleSource garrigueSurface = SurfaceRules.sequence( SurfaceRules.RuleSource garrigueSurface = SurfaceRules.sequence(
SurfaceRules.ifTrue(
SurfaceRules.stoneDepthCheck(0, false, 0, CaveSurface.FLOOR),
SurfaceRules.ifTrue(
isGarrigueGrassSection,
SurfaceRules.state(ModBlocks.LIMESTONE_GRASS_BLOCK.get().defaultBlockState())
)
),
SurfaceRules.ifTrue( SurfaceRules.ifTrue(
SurfaceRules.stoneDepthCheck(0, false, 0, CaveSurface.FLOOR), SurfaceRules.stoneDepthCheck(0, false, 0, CaveSurface.FLOOR),
SurfaceRules.ifTrue( SurfaceRules.ifTrue(
@@ -39,9 +48,9 @@ public class ModNoiseSettings {
), ),
SurfaceRules.ifTrue( SurfaceRules.ifTrue(
SurfaceRules.stoneDepthCheck(0, false, 0, CaveSurface.FLOOR), SurfaceRules.stoneDepthCheck(0, false, 0, CaveSurface.FLOOR),
SurfaceRules.state(ModBlocks.LIMESTONE_BLOCK.get().defaultBlockState()) SurfaceRules.state(Blocks.SANDSTONE.defaultBlockState())
), ),
SurfaceRules.ifTrue(SurfaceRules.stoneDepthCheck(4, false, 0, CaveSurface.FLOOR), SurfaceRules.ifTrue(SurfaceRules.stoneDepthCheck(10, false, 0, CaveSurface.FLOOR),
SurfaceRules.state(ModBlocks.LIMESTONE_BLOCK.get().defaultBlockState())) SurfaceRules.state(ModBlocks.LIMESTONE_BLOCK.get().defaultBlockState()))
); );
@@ -53,11 +62,25 @@ public class ModNoiseSettings {
SurfaceRules.state(ModBlocks.SHALE_GRASS_BLOCK.get().defaultBlockState()) SurfaceRules.state(ModBlocks.SHALE_GRASS_BLOCK.get().defaultBlockState())
) )
), ),
SurfaceRules.ifTrue(
SurfaceRules.stoneDepthCheck(0, false, 0, CaveSurface.FLOOR),
SurfaceRules.ifTrue(
isGranite,
SurfaceRules.state(Blocks.GRANITE.defaultBlockState())
)
),
SurfaceRules.ifTrue( SurfaceRules.ifTrue(
SurfaceRules.stoneDepthCheck(0, false, 0, CaveSurface.FLOOR), SurfaceRules.stoneDepthCheck(0, false, 0, CaveSurface.FLOOR),
SurfaceRules.state(ModBlocks.SHALE_BLOCK.get().defaultBlockState()) SurfaceRules.state(ModBlocks.SHALE_BLOCK.get().defaultBlockState())
), ),
SurfaceRules.ifTrue(SurfaceRules.stoneDepthCheck(4, false, 0, CaveSurface.FLOOR), SurfaceRules.ifTrue(
SurfaceRules.stoneDepthCheck(10, false, 0, CaveSurface.FLOOR),
SurfaceRules.ifTrue(
isGranite,
SurfaceRules.state(Blocks.GRANITE.defaultBlockState())
)
),
SurfaceRules.ifTrue(SurfaceRules.stoneDepthCheck(10, false, 0, CaveSurface.FLOOR),
SurfaceRules.state(ModBlocks.SHALE_BLOCK.get().defaultBlockState())) SurfaceRules.state(ModBlocks.SHALE_BLOCK.get().defaultBlockState()))
); );
@@ -0,0 +1,36 @@
package net.halbear.aotg.registries;
import net.halbear.aotg.AgeoftheGods;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.HolderSet;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.worldgen.BootstrapContext;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import net.neoforged.neoforge.common.world.BiomeModifier;
import net.neoforged.neoforge.common.world.BiomeModifiers;
import net.neoforged.neoforge.registries.NeoForgeRegistries;
public class ModBiomeModifiers {
public static final ResourceKey<BiomeModifier> ADD_TWISTY_TREE =
ResourceKey.create(NeoForgeRegistries.Keys.BIOME_MODIFIERS, Identifier.fromNamespaceAndPath(AgeoftheGods.MODID, "add_twisty_tree"));
public static void bootstrap(BootstrapContext<BiomeModifier> context) {
HolderGetter<PlacedFeature> placedFeatures = context.lookup(Registries.PLACED_FEATURE);
HolderGetter<Biome> biomes = context.lookup(Registries.BIOME);
var placedTreeHolder = placedFeatures.getOrThrow(ModPlacedFeatures.TWISTY_TREE_PLACED_KEY);
var targetBiomes = HolderSet.direct(biomes.getOrThrow(ModBiomes.MAQUIS_SHRUBLAND));
context.register(ADD_TWISTY_TREE, new BiomeModifiers.AddFeaturesBiomeModifier(
targetBiomes,
HolderSet.direct(placedTreeHolder),
GenerationStep.Decoration.VEGETAL_DECORATION
));
}
}
@@ -0,0 +1,36 @@
package net.halbear.aotg.registries;
import net.halbear.aotg.AgeoftheGods;
import net.halbear.aotg.custom.WorldGen.GenerationFeatures.LeafBunchFoliagePlacer;
import net.halbear.aotg.custom.WorldGen.GenerationFeatures.TwistyBranchingTrunkPlacer;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.worldgen.BootstrapContext;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.valueproviders.ConstantInt;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration;
import net.minecraft.world.level.levelgen.feature.featuresize.TwoLayersFeatureSize;
import net.minecraft.world.level.levelgen.feature.foliageplacers.BlobFoliagePlacer;
import net.minecraft.world.level.levelgen.feature.foliageplacers.CherryFoliagePlacer;
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
public class ModConfiguredFeatures {
public static final ResourceKey<ConfiguredFeature<?, ?>> TWISTY_TREE_KEY =
ResourceKey.create(Registries.CONFIGURED_FEATURE, Identifier.fromNamespaceAndPath(AgeoftheGods.MODID, "twisty_tree"));
public static void bootstrap(BootstrapContext<ConfiguredFeature<?, ?>> context) {
context.register(TWISTY_TREE_KEY, new ConfiguredFeature<>(
Feature.TREE,
new TreeConfiguration.TreeConfigurationBuilder(
BlockStateProvider.simple(Blocks.OAK_LOG.defaultBlockState()),
new TwistyBranchingTrunkPlacer(10, 6, 4),
BlockStateProvider.simple(Blocks.OAK_LEAVES.defaultBlockState()),
new LeafBunchFoliagePlacer(ConstantInt.of(1),ConstantInt.of(0)),
new TwoLayersFeatureSize(5, 3, 5)
).build()
));
}
}
@@ -0,0 +1,22 @@
package net.halbear.aotg.registries;
import net.halbear.aotg.AgeoftheGods;
import net.halbear.aotg.custom.WorldGen.GenerationFeatures.LeafBunchFoliagePlacer;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacerType;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
public class ModFoliagePlacers {
public static final DeferredRegister<FoliagePlacerType<?>> FOLIAGE_PLACERS =
DeferredRegister.create(Registries.FOLIAGE_PLACER_TYPE, AgeoftheGods.MODID);
public static final DeferredHolder<FoliagePlacerType<?>, FoliagePlacerType<LeafBunchFoliagePlacer>> LEAF_BUNCH_FOLIAGE_PLACER =
FOLIAGE_PLACERS.register("spherical_foliage_placer", () -> new FoliagePlacerType<>(LeafBunchFoliagePlacer.CODEC));
public static void register(IEventBus eventBus) {
FOLIAGE_PLACERS.register(eventBus);
}
}
@@ -0,0 +1,48 @@
package net.halbear.aotg.registries;
import net.halbear.aotg.AgeoftheGods;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.worldgen.BootstrapContext;
import net.minecraft.data.worldgen.placement.PlacementUtils;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.placement.*;
import java.util.List;
public class ModPlacedFeatures {
public static final ResourceKey<PlacedFeature> TWISTY_TREE_PLACED_KEY =
ResourceKey.create(Registries.PLACED_FEATURE, Identifier.fromNamespaceAndPath(AgeoftheGods.MODID, "twisty_tree_placed"));
public static void bootstrap(BootstrapContext<PlacedFeature> context) {
HolderGetter<ConfiguredFeature<?, ?>> configuredFeatures = context.lookup(Registries.CONFIGURED_FEATURE);
var configuredTreeHolder = configuredFeatures.getOrThrow(ModConfiguredFeatures.TWISTY_TREE_KEY);
context.register(TWISTY_TREE_PLACED_KEY, new PlacedFeature(
configuredTreeHolder,
List.of(
CountPlacement.of(10),
RarityFilter.onAverageOnceEvery(10),
InSquarePlacement.spread(),
PlacementUtils.HEIGHTMAP_OCEAN_FLOOR,
BlockPredicateFilter.forPredicate(
BlockPredicate.matchesBlocks(
new BlockPos(0, -1, 0),
ModBlocks.SHALE_GRASS_BLOCK.get(),
Blocks.SANDSTONE,
ModBlocks.SHALE_BLOCK.get(),
ModBlocks.LIMESTONE_GRASS_BLOCK.get()
)
),
SurfaceWaterDepthFilter.forMaxDepth(0),
BiomeFilter.biome()
)
));
}
}
@@ -0,0 +1,21 @@
package net.halbear.aotg.registries;
import net.halbear.aotg.AgeoftheGods;
import net.halbear.aotg.custom.WorldGen.GenerationFeatures.TwistyBranchingTrunkPlacer;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacerType;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
public class ModTreeGen {
public static final DeferredRegister<TrunkPlacerType<?>> TRUNK_PLACERS =
DeferredRegister.create(Registries.TRUNK_PLACER_TYPE, AgeoftheGods.MODID);
public static final DeferredHolder<TrunkPlacerType<?>, TrunkPlacerType<TwistyBranchingTrunkPlacer>> TWISTY_TRUNK_PLACER =
TRUNK_PLACERS.register("twisty_trunk_placer", () -> new TrunkPlacerType<>(TwistyBranchingTrunkPlacer.CODEC));
public static void register(IEventBus eventBus) {
TRUNK_PLACERS.register(eventBus);
}
}
@@ -152,13 +152,13 @@ public class SkyBoxRendering {
public static void renderCustomSun(RenderLevelStageEvent.AfterSky event, Identifier textureId) { public static void renderCustomSun(RenderLevelStageEvent.AfterSky event, Identifier textureId) {
initBuffers(); initBuffers();
SkyRenderState state = event.getLevelRenderState().skyRenderState; SkyRenderState state = event.getLevelRenderState().skyRenderState;
render2DObjectInSkybox(event, textureId, "Sun",(float)Math.toRadians(-90F),state.sunAngle,new Vector3f(0,100.0f,0),new Vector3f(30.0F,-1.0F,30.0F),new Vector4f(1f,1f,1f,state.rainBrightness), sunBuffer,RenderPipelines.CELESTIAL); render2DObjectInSkybox(event, textureId, "Sun",(float)Math.toRadians(-90F),state.sunAngle,new Vector3f(0,100.0f,0),new Vector3f(30.0F,-1.0F,30.0F),new Vector4f(1f,1f,1f,state.rainBrightness), sunBuffer,CUSTOM_SKYBOX_PIPELINE);//RenderPipelines.CELESTIAL);
} }
public static void renderCustomMoon(RenderLevelStageEvent.AfterSky event, Identifier textureId) { public static void renderCustomMoon(RenderLevelStageEvent.AfterSky event, Identifier textureId) {
initBuffers(); initBuffers();
SkyRenderState state = event.getLevelRenderState().skyRenderState; SkyRenderState state = event.getLevelRenderState().skyRenderState;
render2DObjectInSkybox(event, textureId, "Moon",(float)Math.toRadians(-90F),state.moonAngle,new Vector3f(0,100.0f,0),new Vector3f(30.0F,-1.0F,30.0F),new Vector4f(1f,1f,1f,1f), moonBuffer,RenderPipelines.CELESTIAL); render2DObjectInSkybox(event, textureId, "Moon",(float)Math.toRadians(-90F),state.moonAngle,new Vector3f(0,100.0f,0),new Vector3f(30.0F,-1.0F,30.0F),new Vector4f(1f,1f,1f,1f), moonBuffer,CUSTOM_SKYBOX_PIPELINE);//RenderPipelines.CELESTIAL);
} }
public static float getNightAlpha(long dayTime) { public static float getNightAlpha(long dayTime) {
@@ -2,6 +2,9 @@ package net.halbear.aotg.utility.DataGenerators;
import net.halbear.aotg.AgeoftheGods; import net.halbear.aotg.AgeoftheGods;
import net.halbear.aotg.custom.WorldGen.ModNoiseSettings; import net.halbear.aotg.custom.WorldGen.ModNoiseSettings;
import net.halbear.aotg.registries.ModBiomeModifiers;
import net.halbear.aotg.registries.ModConfiguredFeatures;
import net.halbear.aotg.registries.ModPlacedFeatures;
import net.minecraft.core.HolderGetter; import net.minecraft.core.HolderGetter;
import net.minecraft.core.RegistrySetBuilder; import net.minecraft.core.RegistrySetBuilder;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
@@ -17,6 +20,7 @@ import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider; import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider;
import net.neoforged.neoforge.data.event.GatherDataEvent; import net.neoforged.neoforge.data.event.GatherDataEvent;
import net.neoforged.neoforge.registries.NeoForgeRegistries;
import java.util.Set; import java.util.Set;
@@ -31,7 +35,6 @@ public class AgeOfTheGodsDataGeneration {
@SubscribeEvent @SubscribeEvent
public static void gatherData(GatherDataEvent.Client event) { public static void gatherData(GatherDataEvent.Client event) {
LOGGER.info("gatherData event"); LOGGER.info("gatherData event");
RegistrySetBuilder builder = new RegistrySetBuilder(). RegistrySetBuilder builder = new RegistrySetBuilder().
add(Registries.NOISE, context -> { add(Registries.NOISE, context -> {
context.register(TINY_PATCHY_NOISE, new net.minecraft.world.level.levelgen.synth.NormalNoise.NoiseParameters( context.register(TINY_PATCHY_NOISE, new net.minecraft.world.level.levelgen.synth.NormalNoise.NoiseParameters(
@@ -60,7 +63,10 @@ public class AgeOfTheGodsDataGeneration {
false false
) )
); );
}); })
.add(Registries.CONFIGURED_FEATURE, ModConfiguredFeatures::bootstrap)
.add(Registries.PLACED_FEATURE, ModPlacedFeatures::bootstrap) // Add this
.add(NeoForgeRegistries.Keys.BIOME_MODIFIERS, ModBiomeModifiers::bootstrap);;
LOGGER.info("World Gen something or other"); LOGGER.info("World Gen something or other");
event.createProvider(output -> new DatapackBuiltinEntriesProvider( event.createProvider(output -> new DatapackBuiltinEntriesProvider(
output, output,
@@ -71,11 +77,7 @@ public class AgeOfTheGodsDataGeneration {
} }
@SubscribeEvent @SubscribeEvent
public static void GatherClientData(GatherDataEvent.Client event){ public static void GatherClientData(GatherDataEvent.Server event){
LOGGER.info("GatherClientData event");
DataGenerator generator = event.getGenerator();
PackOutput output = generator.getPackOutput();
// generator.addProvider(true, new AOTGModelProvider(output));
} }
} }
@@ -0,0 +1,26 @@
package net.halbear.aotg.utility.DataGenerators;
import net.halbear.aotg.AgeoftheGods;
import net.halbear.aotg.registries.ModBiomeModifiers;
import net.halbear.aotg.registries.ModConfiguredFeatures;
import net.halbear.aotg.registries.ModPlacedFeatures;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.RegistrySetBuilder;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.PackOutput;
import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider;
import net.neoforged.neoforge.registries.NeoForgeRegistries;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
public class ModWorldGenProvider extends DatapackBuiltinEntriesProvider {
public static final RegistrySetBuilder BUILDER = new RegistrySetBuilder()
.add(Registries.CONFIGURED_FEATURE, ModConfiguredFeatures::bootstrap)
.add(Registries.PLACED_FEATURE, ModPlacedFeatures::bootstrap) // Add this
.add(NeoForgeRegistries.Keys.BIOME_MODIFIERS, ModBiomeModifiers::bootstrap);
public ModWorldGenProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
super(output, registries, BUILDER, Set.of(AgeoftheGods.MODID));
}
}