Mangrove Trees!
- Todo: fix the moss not generating on roots
This commit is contained in:
parent
484129642c
commit
b698b03a9a
|
@ -9,6 +9,10 @@ import com.cursedcauldron.wildbackport.common.registry.WBEnchantments;
|
|||
import com.cursedcauldron.wildbackport.common.registry.WBGameEvents;
|
||||
import com.cursedcauldron.wildbackport.common.registry.WBItems;
|
||||
import com.cursedcauldron.wildbackport.common.registry.WBPositionSources;
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.WBFeatures;
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.RootPlacerType;
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.WBTreeDecorators;
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.WBTrunkPlacers;
|
||||
import com.cursedcauldron.wildbackport.common.registry.entity.WBActivities;
|
||||
import com.cursedcauldron.wildbackport.common.registry.entity.WBEntities;
|
||||
import com.cursedcauldron.wildbackport.common.registry.entity.WBMemoryModules;
|
||||
|
@ -36,12 +40,16 @@ public class WildBackport {
|
|||
WBEnchantments.ENCHANTMENTS.register();
|
||||
WBEntities.ENTITIES.register();
|
||||
WBGameEvents.EVENTS.register();
|
||||
WBFeatures.FEATURES.register();
|
||||
WBItems.ITEMS.register();
|
||||
WBMemoryModules.MEMORIES.register();
|
||||
WBParticleTypes.PARTICLES.register();
|
||||
WBPositionSources.SOURCES.register();
|
||||
RootPlacerType.PLACERS.register();
|
||||
WBSensorTypes.SENSORS.register();
|
||||
WBSoundEvents.SOUNDS.register();
|
||||
WBTreeDecorators.DECORATORS.register();
|
||||
WBTrunkPlacers.PLACERS.register();
|
||||
|
||||
// Tags
|
||||
WBBiomeTags.TAGS.bootstrap();
|
||||
|
|
|
@ -6,6 +6,8 @@ import com.cursedcauldron.wildbackport.common.entities.Tadpole;
|
|||
import com.cursedcauldron.wildbackport.common.entities.Warden;
|
||||
import com.cursedcauldron.wildbackport.common.events.StructureEvent;
|
||||
import com.cursedcauldron.wildbackport.common.registry.entity.WBEntities;
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.WBWorldGeneration;
|
||||
import com.cursedcauldron.wildbackport.core.api.Environment;
|
||||
import com.cursedcauldron.wildbackport.core.api.MobRegistry;
|
||||
|
||||
public class CommonSetup {
|
||||
|
@ -18,13 +20,15 @@ public class CommonSetup {
|
|||
MobRegistry.registerAttributes(WBEntities.FROG, Frog::createAttributes);
|
||||
MobRegistry.registerAttributes(WBEntities.TADPOLE, Tadpole::createAttributes);
|
||||
MobRegistry.registerAttributes(WBEntities.WARDEN, Warden::createAttributes);
|
||||
StructureEvent.bootstrap();
|
||||
// StructureEvent.bootstrap();
|
||||
if (Environment.isFabric()) WBWorldGeneration.bootstrap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs features post bootstrap
|
||||
*/
|
||||
public static void onPostClient() {
|
||||
StructureEvent.bootstrap();
|
||||
public static void onPostCommon() {
|
||||
// StructureEvent.bootstrap();
|
||||
if (Environment.isForge()) WBWorldGeneration.bootstrap();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.cursedcauldron.wildbackport.common.blocks;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.WBWorldGeneration;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.world.level.block.grower.AbstractTreeGrower;
|
||||
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
|
||||
|
@ -8,14 +9,14 @@ import org.jetbrains.annotations.Nullable;
|
|||
import java.util.Random;
|
||||
|
||||
public class MangroveTreeGrower extends AbstractTreeGrower {
|
||||
private final float tallMangroveChance;
|
||||
private final float tallChance;
|
||||
|
||||
public MangroveTreeGrower(float tallMangroveChance) {
|
||||
this.tallMangroveChance = tallMangroveChance;
|
||||
public MangroveTreeGrower(float tallChance) {
|
||||
this.tallChance = tallChance;
|
||||
}
|
||||
|
||||
@Override @Nullable
|
||||
protected Holder<? extends ConfiguredFeature<?, ?>> getConfiguredFeature(Random random, boolean bl) {
|
||||
return null;
|
||||
protected Holder<? extends ConfiguredFeature<?, ?>> getConfiguredFeature(Random random, boolean bees) {
|
||||
return random.nextFloat() < this.tallChance ? WBWorldGeneration.TALL_MANGROVE : WBWorldGeneration.MANGROVE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.cursedcauldron.wildbackport.common.registry.worldgen;
|
||||
|
||||
import com.cursedcauldron.wildbackport.WildBackport;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.placers.MangroveRootPlacer;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.placers.RootPlacer;
|
||||
import com.cursedcauldron.wildbackport.core.api.CoreRegistry;
|
||||
import com.mojang.serialization.Codec;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class RootPlacerType<P extends RootPlacer> {
|
||||
public static final CoreRegistry<RootPlacerType<?>> PLACERS = CoreRegistry.create(WBRegistries.ROOT_PLACER_TYPES.getSecond(), WildBackport.MOD_ID);
|
||||
|
||||
public static final Supplier<RootPlacerType<MangroveRootPlacer>> MANGROVE_ROOT_PLACER = PLACERS.register("mangrove_root_placer", () -> new RootPlacerType<>(MangroveRootPlacer.CODEC));
|
||||
|
||||
|
||||
private final Codec<P> codec;
|
||||
|
||||
private RootPlacerType(Codec<P> codec) {
|
||||
this.codec = codec;
|
||||
}
|
||||
|
||||
public Codec<P> codec() {
|
||||
return this.codec;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.cursedcauldron.wildbackport.common.registry.worldgen;
|
||||
|
||||
import com.cursedcauldron.wildbackport.WildBackport;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.features.RootedTreeConfig;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.features.RootedTreeFeature;
|
||||
import com.cursedcauldron.wildbackport.core.api.CoreRegistry;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
//<>
|
||||
|
||||
public class WBFeatures {
|
||||
public static final CoreRegistry<Feature<?>> FEATURES = CoreRegistry.create(Registry.FEATURE, WildBackport.MOD_ID);
|
||||
|
||||
public static final Supplier<Feature<RootedTreeConfig>> TREE = FEATURES.register("tree", () -> new RootedTreeFeature(RootedTreeConfig.CODEC));
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.cursedcauldron.wildbackport.common.registry.worldgen;
|
||||
|
||||
import com.cursedcauldron.wildbackport.WildBackport;
|
||||
import com.cursedcauldron.wildbackport.core.mixin.access.RegistryAccessor;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
//<>
|
||||
|
||||
public class WBRegistries {
|
||||
public static final Pair<ResourceKey<Registry<RootPlacerType<?>>>, Registry<RootPlacerType<?>>> ROOT_PLACER_TYPES = create("worldgen/root_placer_type", registry -> RootPlacerType.MANGROVE_ROOT_PLACER.get());
|
||||
|
||||
private static <T> Pair<ResourceKey<Registry<T>>, Registry<T>> create(String key, Registry.RegistryBootstrap<T> bootstrap) {
|
||||
ResourceKey<Registry<T>> resource = ResourceKey.createRegistryKey(new ResourceLocation(WildBackport.MOD_ID, key));
|
||||
Registry<T> registry = RegistryAccessor.callRegisterSimple(resource, bootstrap);
|
||||
return Pair.of(resource, registry);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.cursedcauldron.wildbackport.common.registry.worldgen;
|
||||
|
||||
import com.cursedcauldron.wildbackport.WildBackport;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.decorator.AttachedToLeavesDecorator;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.decorator.WeightedLeaveVineDecorator;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.placers.UpwardBranchingTrunk;
|
||||
import com.cursedcauldron.wildbackport.core.api.CoreRegistry;
|
||||
import com.cursedcauldron.wildbackport.core.mixin.access.TreeDecoratorTypeAccessor;
|
||||
import com.cursedcauldron.wildbackport.core.mixin.access.TrunkPlacerTypeAccessor;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecoratorType;
|
||||
import net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacerType;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
//<>
|
||||
|
||||
public class WBTreeDecorators {
|
||||
public static final CoreRegistry<TreeDecoratorType<?>> DECORATORS = CoreRegistry.create(Registry.TREE_DECORATOR_TYPES, WildBackport.MOD_ID);
|
||||
|
||||
public static final Supplier<TreeDecoratorType<WeightedLeaveVineDecorator>> WEIGHTED_LEAVE_VINE = DECORATORS.register("leave_vine", () -> TreeDecoratorTypeAccessor.createTreeDecoratorType(WeightedLeaveVineDecorator.CODEC));
|
||||
public static final Supplier<TreeDecoratorType<AttachedToLeavesDecorator>> ATTACHED_TO_LEAVES = DECORATORS.register("attached_to_leaves", () -> TreeDecoratorTypeAccessor.createTreeDecoratorType(AttachedToLeavesDecorator.CODEC));
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.cursedcauldron.wildbackport.common.registry.worldgen;
|
||||
|
||||
import com.cursedcauldron.wildbackport.WildBackport;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.placers.UpwardBranchingTrunk;
|
||||
import com.cursedcauldron.wildbackport.core.api.CoreRegistry;
|
||||
import com.cursedcauldron.wildbackport.core.mixin.access.TrunkPlacerTypeAccessor;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacerType;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
//<>
|
||||
|
||||
public class WBTrunkPlacers {
|
||||
public static final CoreRegistry<TrunkPlacerType<?>> PLACERS = CoreRegistry.create(Registry.TRUNK_PLACER_TYPES, WildBackport.MOD_ID);
|
||||
|
||||
public static final Supplier<TrunkPlacerType<UpwardBranchingTrunk>> UPWARDS_BRANCHING_TRUNK = PLACERS.register("upward_branching_trunk", () -> TrunkPlacerTypeAccessor.createTrunkPlacerType(UpwardBranchingTrunk.CODEC));
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package com.cursedcauldron.wildbackport.common.registry.worldgen;
|
||||
|
||||
import com.cursedcauldron.wildbackport.WildBackport;
|
||||
import com.cursedcauldron.wildbackport.common.blocks.MangrovePropaguleBlock;
|
||||
import com.cursedcauldron.wildbackport.common.registry.WBBlocks;
|
||||
import com.cursedcauldron.wildbackport.common.tag.WBBlockTags;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.decorator.AttachedToLeavesDecorator;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.decorator.LayerRootDecorator;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.decorator.MangroveRootPlacement;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.decorator.WeightedLeaveVineDecorator;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.features.RootedTreeConfig;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.placers.MangroveRootPlacer;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.placers.UpwardBranchingTrunk;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.data.BuiltinRegistries;
|
||||
import net.minecraft.data.worldgen.placement.PlacementUtils;
|
||||
import net.minecraft.util.valueproviders.ConstantInt;
|
||||
import net.minecraft.util.valueproviders.UniformInt;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
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.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.WeightedPlacedFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.RandomFeatureConfiguration;
|
||||
import net.minecraft.world.level.levelgen.feature.featuresize.TwoLayersFeatureSize;
|
||||
import net.minecraft.world.level.levelgen.feature.foliageplacers.RandomSpreadFoliagePlacer;
|
||||
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
|
||||
import net.minecraft.world.level.levelgen.feature.stateproviders.RandomizedIntStateProvider;
|
||||
import net.minecraft.world.level.levelgen.feature.treedecorators.BeehiveDecorator;
|
||||
import net.minecraft.world.level.levelgen.placement.BiomeFilter;
|
||||
import net.minecraft.world.level.levelgen.placement.BlockPredicateFilter;
|
||||
import net.minecraft.world.level.levelgen.placement.CountPlacement;
|
||||
import net.minecraft.world.level.levelgen.placement.InSquarePlacement;
|
||||
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementModifier;
|
||||
import net.minecraft.world.level.levelgen.placement.SurfaceWaterDepthFilter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
//<>
|
||||
|
||||
public class WBWorldGeneration {
|
||||
public static void bootstrap() {}
|
||||
|
||||
// Mangrove Swamp
|
||||
|
||||
public static final Holder<ConfiguredFeature<RootedTreeConfig, ?>> MANGROVE = config("mangrove", WBFeatures.TREE.get(), new RootedTreeConfig.Builder(
|
||||
BlockStateProvider.simple(WBBlocks.MANGROVE_LOG.get()),
|
||||
new UpwardBranchingTrunk(2, 1, 4, UniformInt.of(1, 4), 0.5F, UniformInt.of(0, 1), Registry.BLOCK.getOrCreateTag(WBBlockTags.MANGROVE_LOGS_CAN_GROW_THROUGH)),
|
||||
BlockStateProvider.simple(WBBlocks.MANGROVE_LEAVES.get()),
|
||||
new RandomSpreadFoliagePlacer(ConstantInt.of(3), ConstantInt.of(0), ConstantInt.of(2), 70),
|
||||
Optional.of(new MangroveRootPlacer(UniformInt.of(1, 3), BlockStateProvider.simple(WBBlocks.MANGROVE_ROOTS.get()), Optional.of(new LayerRootDecorator(BlockStateProvider.simple(Blocks.MOSS_CARPET), 0.5F)), new MangroveRootPlacement(Registry.BLOCK.getOrCreateTag(WBBlockTags.MANGROVE_ROOTS_CAN_GROW_THROUGH), HolderSet.direct(Block::builtInRegistryHolder, WBBlocks.MUD.get(), WBBlocks.MUDDY_MANGROVE_ROOTS.get()), BlockStateProvider.simple(WBBlocks.MUDDY_MANGROVE_ROOTS.get()), 8, 15, 0.2F))),
|
||||
new TwoLayersFeatureSize(2, 0, 2)
|
||||
).decorators(List.of(
|
||||
new WeightedLeaveVineDecorator(0.125F),
|
||||
new AttachedToLeavesDecorator(0.14F, 1, 0, new RandomizedIntStateProvider(BlockStateProvider.simple(WBBlocks.MANGROVE_PROPAGULE.get().defaultBlockState().setValue(MangrovePropaguleBlock.HANGING, true)), MangrovePropaguleBlock.AGE, UniformInt.of(0, 4)), 2, List.of(Direction.DOWN)),
|
||||
new BeehiveDecorator(0.01F)
|
||||
)).ignoreVines().build());
|
||||
|
||||
public static final Holder<ConfiguredFeature<RootedTreeConfig, ?>> TALL_MANGROVE = config("tall_mangrove", WBFeatures.TREE.get(), new RootedTreeConfig.Builder(
|
||||
BlockStateProvider.simple(WBBlocks.MANGROVE_LOG.get()),
|
||||
new UpwardBranchingTrunk(4, 1, 9, UniformInt.of(1, 6), 0.5F, UniformInt.of(0, 1), Registry.BLOCK.getOrCreateTag(WBBlockTags.MANGROVE_LOGS_CAN_GROW_THROUGH)),
|
||||
BlockStateProvider.simple(WBBlocks.MANGROVE_LEAVES.get()),
|
||||
new RandomSpreadFoliagePlacer(ConstantInt.of(3), ConstantInt.of(0), ConstantInt.of(2), 70),
|
||||
Optional.of(new MangroveRootPlacer(UniformInt.of(3, 7), BlockStateProvider.simple(WBBlocks.MANGROVE_ROOTS.get()), Optional.of(new LayerRootDecorator(BlockStateProvider.simple(Blocks.MOSS_CARPET), 0.5F)), new MangroveRootPlacement(Registry.BLOCK.getOrCreateTag(WBBlockTags.MANGROVE_ROOTS_CAN_GROW_THROUGH), HolderSet.direct(Block::builtInRegistryHolder, WBBlocks.MUD.get(), WBBlocks.MUDDY_MANGROVE_ROOTS.get()), BlockStateProvider.simple(WBBlocks.MUDDY_MANGROVE_ROOTS.get()), 8, 15, 0.2F))),
|
||||
new TwoLayersFeatureSize(3, 0, 2)
|
||||
).decorators(List.of(
|
||||
new WeightedLeaveVineDecorator(0.125F),
|
||||
new AttachedToLeavesDecorator(0.14F, 1, 0, new RandomizedIntStateProvider(BlockStateProvider.simple(WBBlocks.MANGROVE_PROPAGULE.get().defaultBlockState().setValue(MangrovePropaguleBlock.HANGING, true)), MangrovePropaguleBlock.AGE, UniformInt.of(0, 4)), 2, List.of(Direction.DOWN)),
|
||||
new BeehiveDecorator(0.01F)
|
||||
)).ignoreVines().build());
|
||||
|
||||
public static final Holder<PlacedFeature> MANGROVE_CHECKED = place("mangrove_checked", MANGROVE, PlacementUtils.filteredByBlockSurvival(WBBlocks.MANGROVE_PROPAGULE.get()));
|
||||
public static final Holder<PlacedFeature> TALL_MANGROVE_CHECKED = place("tall_mangrove_checked", TALL_MANGROVE, PlacementUtils.filteredByBlockSurvival(WBBlocks.MANGROVE_PROPAGULE.get()));
|
||||
|
||||
public static final Holder<ConfiguredFeature<RandomFeatureConfiguration, ?>> MANGROVE_VEGETATION = config("mangrove_vegetation", Feature.RANDOM_SELECTOR, new RandomFeatureConfiguration(List.of(new WeightedPlacedFeature(TALL_MANGROVE_CHECKED, 0.85F)), MANGROVE_CHECKED));
|
||||
public static final Holder<PlacedFeature> TREES_MANGROVE = place("trees_mangrove", MANGROVE_VEGETATION, CountPlacement.of(25), InSquarePlacement.spread(), SurfaceWaterDepthFilter.forMaxDepth(5), PlacementUtils.HEIGHTMAP_OCEAN_FLOOR, BiomeFilter.biome(), BlockPredicateFilter.forPredicate(BlockPredicate.wouldSurvive(WBBlocks.MANGROVE_PROPAGULE.get().defaultBlockState(), BlockPos.ZERO)));
|
||||
|
||||
|
||||
// Deep Dark
|
||||
|
||||
// Registry
|
||||
|
||||
public static <FC extends FeatureConfiguration, F extends Feature<FC>> Holder<ConfiguredFeature<FC, ?>> config(String key, F feature, FC configuration) {
|
||||
return BuiltinRegistries.registerExact(BuiltinRegistries.CONFIGURED_FEATURE, WildBackport.MOD_ID + ":" + key, new ConfiguredFeature<>(feature, configuration));
|
||||
}
|
||||
|
||||
public static Holder<PlacedFeature> place(String key, Holder<? extends ConfiguredFeature<?, ?>> feature, PlacementModifier... placements) {
|
||||
return BuiltinRegistries.registerExact(BuiltinRegistries.PLACED_FEATURE, WildBackport.MOD_ID + ":" + key, new PlacedFeature(Holder.hackyErase(feature), List.copyOf(List.of(placements))));
|
||||
}
|
||||
}
|
|
@ -9,8 +9,14 @@ import net.minecraft.world.level.block.Block;
|
|||
public class WBBlockTags {
|
||||
public static final TagRegistry<Block> TAGS = TagRegistry.create(Registry.BLOCK, WildBackport.MOD_ID);
|
||||
|
||||
public static final TagKey<Block> FROG_PREFER_JUMP_TO = TAGS.create("frog_prefer_jump_to");
|
||||
public static final TagKey<Block> FROGS_SPAWNABLE_ON = TAGS.create("frogs_spawnable_on");
|
||||
public static final TagKey<Block> SCULK_REPLACEABLE = TAGS.create("sculk_replaceable");
|
||||
public static final TagKey<Block> SCULK_REPLACEABLE_WORLD_GEN = TAGS.create("sculk_replaceable_world_gen");
|
||||
// Mangrove Swamp
|
||||
|
||||
public static final TagKey<Block> MANGROVE_LOGS_CAN_GROW_THROUGH = TAGS.create("mangrove_logs_can_grow_through");
|
||||
public static final TagKey<Block> MANGROVE_ROOTS_CAN_GROW_THROUGH = TAGS.create("mangrove_roots_can_grow_through");
|
||||
public static final TagKey<Block> FROG_PREFER_JUMP_TO = TAGS.create("frog_prefer_jump_to");
|
||||
public static final TagKey<Block> FROGS_SPAWNABLE_ON = TAGS.create("frogs_spawnable_on");
|
||||
|
||||
// Deep Dark
|
||||
public static final TagKey<Block> SCULK_REPLACEABLE = TAGS.create("sculk_replaceable");
|
||||
public static final TagKey<Block> SCULK_REPLACEABLE_WORLD_GEN = TAGS.create("sculk_replaceable_world_gen");
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package com.cursedcauldron.wildbackport.common.worldgen.decorator;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.WBTreeDecorators;
|
||||
import com.cursedcauldron.wildbackport.common.utils.ModUtils;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.LevelSimulatedReader;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
|
||||
import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecorator;
|
||||
import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecoratorType;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class AttachedToLeavesDecorator extends TreeDecorator {
|
||||
public static final Codec<AttachedToLeavesDecorator> CODEC = RecordCodecBuilder.create(instance -> {
|
||||
return instance.group(Codec.floatRange(0.0F, 1.0F).fieldOf("probability").forGetter(decorator -> {
|
||||
return decorator.probability;
|
||||
}), Codec.intRange(0, 16).fieldOf("exclusion_radius_xz").forGetter(decorator -> {
|
||||
return decorator.exclusionRadiusXZ;
|
||||
}), Codec.intRange(0, 16).fieldOf("exclusion_radius_y").forGetter(decorator -> {
|
||||
return decorator.exclusionRadiusY;
|
||||
}), BlockStateProvider.CODEC.fieldOf("block_provider").forGetter(decorator -> {
|
||||
return decorator.blockProvider;
|
||||
}), Codec.intRange(1, 16).fieldOf("required_empty_blocks").forGetter(decorator -> {
|
||||
return decorator.requiredEmptyBlocks;
|
||||
}), Direction.CODEC.listOf().fieldOf("directions").forGetter(decorator -> {
|
||||
return decorator.directions;
|
||||
})).apply(instance, AttachedToLeavesDecorator::new);
|
||||
});
|
||||
protected final float probability;
|
||||
protected final int exclusionRadiusXZ;
|
||||
protected final int exclusionRadiusY;
|
||||
protected final BlockStateProvider blockProvider;
|
||||
protected final int requiredEmptyBlocks;
|
||||
protected final List<Direction> directions;
|
||||
|
||||
public AttachedToLeavesDecorator(float probability, int exclusionRadiusXZ, int exclusionRadiusY, BlockStateProvider blockProvider, int requiredEmptyBlocks, List<Direction> directions) {
|
||||
this.probability = probability;
|
||||
this.exclusionRadiusXZ = exclusionRadiusXZ;
|
||||
this.exclusionRadiusY = exclusionRadiusY;
|
||||
this.blockProvider = blockProvider;
|
||||
this.requiredEmptyBlocks = requiredEmptyBlocks;
|
||||
this.directions = directions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void place(LevelSimulatedReader level, BiConsumer<BlockPos, BlockState> replacer, Random random, List<BlockPos> trunkPositions, List<BlockPos> foliagePositions) {
|
||||
HashSet<BlockPos> positions = new HashSet<>();
|
||||
for (BlockPos pos : ModUtils.copyShuffled(new ObjectArrayList<>(foliagePositions), random)) {
|
||||
Direction direction = Util.getRandom(this.directions, random);
|
||||
BlockPos offset = pos.relative(direction);
|
||||
if (!positions.contains(offset) && random.nextFloat() < this.probability && this.meetsRequiredEmptyBlocks(level, pos, direction)) {
|
||||
BlockPos minRadius = offset.offset(-this.exclusionRadiusXZ, -this.exclusionRadiusY, -this.exclusionRadiusXZ);
|
||||
BlockPos maxRadius = offset.offset(this.exclusionRadiusXZ, this.exclusionRadiusY, this.exclusionRadiusXZ);
|
||||
for (BlockPos position : BlockPos.betweenClosed(minRadius, maxRadius)) {
|
||||
positions.add(position.immutable());
|
||||
}
|
||||
|
||||
replacer.accept(offset, this.blockProvider.getState(random, offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean meetsRequiredEmptyBlocks(LevelSimulatedReader level, BlockPos pos, Direction direction) {
|
||||
for (int i = 1; i <= this.requiredEmptyBlocks; i++) {
|
||||
if (!Feature.isAir(level, pos.relative(direction, i))) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TreeDecoratorType<?> type() {
|
||||
return WBTreeDecorators.ATTACHED_TO_LEAVES.get();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.cursedcauldron.wildbackport.common.worldgen.decorator;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
|
||||
|
||||
public record LayerRootDecorator(BlockStateProvider aboveRootProvider, float aboveRootPlacementChance) {
|
||||
public static final Codec<LayerRootDecorator> CODEC = RecordCodecBuilder.create(instance -> {
|
||||
return instance.group(BlockStateProvider.CODEC.fieldOf("above_root_provider").forGetter(decorator -> {
|
||||
return decorator.aboveRootProvider;
|
||||
}), Codec.floatRange(0.0F, 1.0F).fieldOf("above_root_placement_chance").forGetter(decorator -> {
|
||||
return decorator.aboveRootPlacementChance;
|
||||
})).apply(instance, LayerRootDecorator::new);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.cursedcauldron.wildbackport.common.worldgen.decorator;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.RegistryCodecs;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
|
||||
|
||||
public record MangroveRootPlacement(HolderSet<Block> canGrowThrough, HolderSet<Block> muddyRootsIn, BlockStateProvider muddyRootsProvider, int maxRootWidth, int maxRootLength, float randomSkewChance) {
|
||||
public static final Codec<MangroveRootPlacement> CODEC = RecordCodecBuilder.create(instance -> {
|
||||
return instance.group(RegistryCodecs.homogeneousList(Registry.BLOCK_REGISTRY).fieldOf("can_grow_through").forGetter(placer -> {
|
||||
return placer.canGrowThrough;
|
||||
}), RegistryCodecs.homogeneousList(Registry.BLOCK_REGISTRY).fieldOf("muddy_roots_in").forGetter(placer -> {
|
||||
return placer.muddyRootsIn;
|
||||
}), BlockStateProvider.CODEC.fieldOf("muddy_roots_provider").forGetter(placer -> {
|
||||
return placer.muddyRootsProvider;
|
||||
}), Codec.intRange(1, 12).fieldOf("max_root_width").forGetter(placer -> {
|
||||
return placer.maxRootWidth;
|
||||
}), Codec.intRange(1, 64).fieldOf("max_root_length").forGetter(placer -> {
|
||||
return placer.maxRootLength;
|
||||
}), Codec.floatRange(0.0F, 1.0F).fieldOf("random_skew_chance").forGetter(placer -> {
|
||||
return placer.randomSkewChance;
|
||||
})).apply(instance, MangroveRootPlacement::new);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.cursedcauldron.wildbackport.common.worldgen.decorator;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.WBTreeDecorators;
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.LevelSimulatedReader;
|
||||
import net.minecraft.world.level.block.VineBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.treedecorators.LeaveVineDecorator;
|
||||
import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecorator;
|
||||
import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecoratorType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
//<>
|
||||
|
||||
public class WeightedLeaveVineDecorator extends TreeDecorator {
|
||||
public static final Codec<WeightedLeaveVineDecorator> CODEC = Codec.floatRange(0.0F, 1.0F).fieldOf("probability").xmap(WeightedLeaveVineDecorator::new, decorator -> {
|
||||
return decorator.probability;
|
||||
}).codec();
|
||||
private final float probability;
|
||||
|
||||
public WeightedLeaveVineDecorator(float probability) {
|
||||
this.probability = probability;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void place(LevelSimulatedReader level, BiConsumer<BlockPos, BlockState> replacer, Random random, List<BlockPos> trunkPositions, List<BlockPos> foliagePositions) {
|
||||
foliagePositions.forEach(pos -> {
|
||||
if (random.nextFloat() < this.probability && Feature.isAir(level, pos.west())) addHangingVine(level, pos.west(), VineBlock.EAST, replacer);
|
||||
if (random.nextFloat() < this.probability && Feature.isAir(level, pos.east())) addHangingVine(level, pos.east(), VineBlock.WEST, replacer);
|
||||
if (random.nextFloat() < this.probability && Feature.isAir(level, pos.north())) addHangingVine(level, pos.north(), VineBlock.SOUTH, replacer);
|
||||
if (random.nextFloat() < this.probability && Feature.isAir(level, pos.south())) addHangingVine(level, pos.south(), VineBlock.NORTH, replacer);
|
||||
});
|
||||
}
|
||||
|
||||
private static void addHangingVine(LevelSimulatedReader level, BlockPos pos, BooleanProperty property, BiConsumer<BlockPos, BlockState> replacer) {
|
||||
LeaveVineDecorator.placeVine(replacer, pos, property);
|
||||
pos = pos.below();
|
||||
|
||||
for (int i = 4; Feature.isAir(level, pos) && i > 0; --i) {
|
||||
LeaveVineDecorator.placeVine(replacer, pos, property);
|
||||
pos = pos.below();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TreeDecoratorType<?> type() {
|
||||
return WBTreeDecorators.WEIGHTED_LEAVE_VINE.get();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package com.cursedcauldron.wildbackport.common.worldgen.features;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.placers.RootPlacer;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration;
|
||||
import net.minecraft.world.level.levelgen.feature.featuresize.FeatureSize;
|
||||
import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacer;
|
||||
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
|
||||
import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecorator;
|
||||
import net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
//<>
|
||||
|
||||
public class RootedTreeConfig extends TreeConfiguration {
|
||||
public static final Codec<RootedTreeConfig> CODEC = RecordCodecBuilder.create(instance -> {
|
||||
return instance.group(BlockStateProvider.CODEC.fieldOf("trunk_provider").forGetter(config -> {
|
||||
return config.trunkProvider;
|
||||
}), TrunkPlacer.CODEC.fieldOf("trunk_placer").forGetter(config -> {
|
||||
return config.trunkPlacer;
|
||||
}), BlockStateProvider.CODEC.fieldOf("foliage_provider").forGetter(config -> {
|
||||
return config.foliageProvider;
|
||||
}), FoliagePlacer.CODEC.fieldOf("foliage_placer").forGetter(config -> {
|
||||
return config.foliagePlacer;
|
||||
}), RootPlacer.CODEC.optionalFieldOf("root_placer").forGetter(config -> {
|
||||
return config.rootPlacer;
|
||||
}), BlockStateProvider.CODEC.fieldOf("dirt_provider").forGetter(config -> {
|
||||
return config.dirtProvider;
|
||||
}), FeatureSize.CODEC.fieldOf("minimum_size").forGetter(config -> {
|
||||
return config.minimumSize;
|
||||
}), TreeDecorator.CODEC.listOf().fieldOf("decorators").forGetter(config -> {
|
||||
return config.decorators;
|
||||
}), Codec.BOOL.fieldOf("ignore_vines").orElse(false).forGetter(config -> {
|
||||
return config.ignoreVines;
|
||||
}), Codec.BOOL.fieldOf("force_dirt").orElse(false).forGetter(config -> {
|
||||
return config.forceDirt;
|
||||
})).apply(instance, RootedTreeConfig::new);
|
||||
});
|
||||
public final Optional<RootPlacer> rootPlacer;
|
||||
|
||||
protected RootedTreeConfig(BlockStateProvider trunkProvider, TrunkPlacer trunkPlacer, BlockStateProvider foliageProvider, FoliagePlacer foliagePlacer, Optional<RootPlacer> rootPlacer, BlockStateProvider dirtProvider, FeatureSize minimumSize, List<TreeDecorator> decorators, boolean ignoreVines, boolean forceDirt) {
|
||||
super(trunkProvider, trunkPlacer, foliageProvider, foliagePlacer, dirtProvider, minimumSize, decorators, ignoreVines, forceDirt);
|
||||
this.rootPlacer = rootPlacer;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
public final BlockStateProvider trunkProvider;
|
||||
private final TrunkPlacer trunkPlacer;
|
||||
public final BlockStateProvider foliageProvider;
|
||||
private final FoliagePlacer foliagePlacer;
|
||||
private final Optional<RootPlacer> rootPlacer;
|
||||
private BlockStateProvider dirtProvider;
|
||||
private final FeatureSize minimumSize;
|
||||
private List<TreeDecorator> decorators = ImmutableList.of();
|
||||
private boolean ignoreVines;
|
||||
private boolean forceDirt;
|
||||
|
||||
public Builder(BlockStateProvider trunkProvider, TrunkPlacer trunkPlacer, BlockStateProvider foliageProvider, FoliagePlacer foliagePlacer, Optional<RootPlacer> rootPlacer, FeatureSize minimumSize) {
|
||||
this.trunkProvider = trunkProvider;
|
||||
this.trunkPlacer = trunkPlacer;
|
||||
this.foliageProvider = foliageProvider;
|
||||
this.dirtProvider = BlockStateProvider.simple(Blocks.DIRT);
|
||||
this.foliagePlacer = foliagePlacer;
|
||||
this.rootPlacer = rootPlacer;
|
||||
this.minimumSize = minimumSize;
|
||||
}
|
||||
|
||||
public Builder(BlockStateProvider trunkProvider, TrunkPlacer trunkPlacer, BlockStateProvider foliageProvider, FoliagePlacer foliagePlacer, FeatureSize minimumSize) {
|
||||
this(trunkProvider, trunkPlacer, foliageProvider, foliagePlacer, Optional.empty(), minimumSize);
|
||||
}
|
||||
|
||||
public Builder dirtProvider(BlockStateProvider dirtProvider) {
|
||||
this.dirtProvider = dirtProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder decorators(List<TreeDecorator> decorators) {
|
||||
this.decorators = decorators;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder ignoreVines() {
|
||||
this.ignoreVines = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder forceDirt() {
|
||||
this.forceDirt = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RootedTreeConfig build() {
|
||||
return new RootedTreeConfig(this.trunkProvider, this.trunkPlacer, this.foliageProvider, this.foliagePlacer, this.rootPlacer, this.dirtProvider, this.minimumSize, this.decorators, this.ignoreVines, this.forceDirt);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
package com.cursedcauldron.wildbackport.common.worldgen.features;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.placers.UpwardBranchingTrunk;
|
||||
import com.cursedcauldron.wildbackport.core.mixin.access.TreeFeatureAccessor;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelSimulatedReader;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.TreeFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacer;
|
||||
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
||||
import net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape;
|
||||
import net.minecraft.world.phys.shapes.DiscreteVoxelShape;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
//<>
|
||||
|
||||
public class RootedTreeFeature extends Feature<RootedTreeConfig> {
|
||||
public RootedTreeFeature(Codec<RootedTreeConfig> codec) {
|
||||
super(codec);
|
||||
}
|
||||
|
||||
private boolean generate(WorldGenLevel level, Random random, BlockPos pos, BiConsumer<BlockPos, BlockState> rootPlacerReplacer, BiConsumer<BlockPos, BlockState> trunkPlacerReplacer, BiConsumer<BlockPos, BlockState> foliagePlacerReplacer, RootedTreeConfig config) {
|
||||
int treeHeight = config.trunkPlacer.getTreeHeight(random);
|
||||
int foliageHeight = config.foliagePlacer.foliageHeight(random, treeHeight, config);
|
||||
int trunkLength = treeHeight - foliageHeight;
|
||||
int foliageRadius = config.foliagePlacer.foliageRadius(random, trunkLength);
|
||||
BlockPos origin = config.rootPlacer.map(rootPlacer -> rootPlacer.trunkOffset(pos, random)).orElse(pos);
|
||||
int minHeight = Math.min(pos.getY(), origin.getY());
|
||||
int maxHeight = Math.max(pos.getY(), origin.getY()) + treeHeight + 1;
|
||||
if (minHeight >= level.getMinBuildHeight() + 1 && maxHeight <= level.getMaxBuildHeight()) {
|
||||
OptionalInt clippedHeight = config.minimumSize.minClippedHeight();
|
||||
int topPosition = this.getTopPosition(level, treeHeight, origin, config);
|
||||
if (topPosition >= treeHeight || clippedHeight.isPresent() && topPosition >= clippedHeight.getAsInt()) {
|
||||
if (config.rootPlacer.isPresent() && !config.rootPlacer.get().generate(level, rootPlacerReplacer, random, pos, origin, config)) {
|
||||
return false;
|
||||
} else {
|
||||
List<FoliagePlacer.FoliageAttachment> foliage = config.trunkPlacer.placeTrunk(level, trunkPlacerReplacer, random, topPosition, origin, config);
|
||||
foliage.forEach(node -> config.foliagePlacer.createFoliage(level, foliagePlacerReplacer, random, config, topPosition, node, foliageHeight, foliageRadius));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private int getTopPosition(LevelSimulatedReader level, int height, BlockPos pos, RootedTreeConfig config) {
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
for (int y = 0; y <= height + 1; ++y) {
|
||||
int size = config.minimumSize.getSizeAtHeight(height, y);
|
||||
|
||||
for (int x = -size; x <= size; ++x) {
|
||||
for (int z = -size; z <= size; ++z) {
|
||||
mutable.setWithOffset(pos, x, y, z);
|
||||
boolean isValid = (TreeFeature.validTreePos(level, pos) || level.isStateAtPosition(pos, state -> state.is(BlockTags.LOGS))) || (config.trunkPlacer instanceof UpwardBranchingTrunk placer && level.isStateAtPosition(pos, state -> state.is(placer.canGrowThrough)));
|
||||
if (!isValid || !config.ignoreVines && TreeFeatureAccessor.isVine(level, mutable)) return y - 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean place(FeaturePlaceContext<RootedTreeConfig> context) {
|
||||
WorldGenLevel level = context.level();
|
||||
Random random = context.random();
|
||||
BlockPos pos = context.origin();
|
||||
RootedTreeConfig config = context.config();
|
||||
HashSet<BlockPos> rootPos = Sets.newHashSet();
|
||||
HashSet<BlockPos> trunkPos = Sets.newHashSet();
|
||||
HashSet<BlockPos> foliagePos = Sets.newHashSet();
|
||||
HashSet<BlockPos> decoratorPos = Sets.newHashSet();
|
||||
BiConsumer<BlockPos, BlockState> rootReplacer = (position, state) -> {
|
||||
rootPos.add(position.immutable());
|
||||
level.setBlock(position, state, 19);
|
||||
};
|
||||
BiConsumer<BlockPos, BlockState> trunkReplacer = (position, state) -> {
|
||||
trunkPos.add(position.immutable());
|
||||
level.setBlock(position, state, 19);
|
||||
};
|
||||
BiConsumer<BlockPos, BlockState> foliageReplacer = (position, state) -> {
|
||||
foliagePos.add(position.immutable());
|
||||
level.setBlock(position, state, 19);
|
||||
};
|
||||
BiConsumer<BlockPos, BlockState> decoratorReplacer = (position, state) -> {
|
||||
decoratorPos.add(position.immutable());
|
||||
level.setBlock(position, state, 19);
|
||||
};
|
||||
boolean generate = this.generate(level, random, pos, rootReplacer, trunkReplacer, foliageReplacer, config);
|
||||
if (!generate || trunkPos.isEmpty() && foliagePos.isEmpty()) return false;
|
||||
if (!config.decorators.isEmpty()) {
|
||||
ArrayList<BlockPos> rootPositions = Lists.newArrayList(rootPos);
|
||||
ArrayList<BlockPos> trunkPositions = Lists.newArrayList(trunkPos);
|
||||
ArrayList<BlockPos> foliagePositions = Lists.newArrayList(foliagePos);
|
||||
trunkPositions.sort(Comparator.comparingInt(Vec3i::getY));
|
||||
foliagePositions.sort(Comparator.comparingInt(Vec3i::getY));
|
||||
rootPositions.sort(Comparator.comparingInt(Vec3i::getY));
|
||||
config.decorators.forEach(treeDecorator -> treeDecorator.place(level, decoratorReplacer, random, trunkPositions, foliagePositions));
|
||||
}
|
||||
|
||||
return BoundingBox.encapsulatingPositions(Iterables.concat(trunkPos, foliagePos, decoratorPos)).map(box -> {
|
||||
DiscreteVoxelShape shape = RootedTreeFeature.placeLogsAndLeaves(level, box, trunkPos, decoratorPos);
|
||||
StructureTemplate.updateShapeAtEdge(level, Block.UPDATE_ALL, shape, box.minX(), box.minY(), box.minZ());
|
||||
return true;
|
||||
}).orElse(false);
|
||||
}
|
||||
|
||||
private static DiscreteVoxelShape placeLogsAndLeaves(LevelAccessor level, BoundingBox box, Set<BlockPos> trunkPositions, Set<BlockPos> decoratorPositions) {
|
||||
ArrayList<Set<BlockPos>> positions = Lists.newArrayList();
|
||||
BitSetDiscreteVoxelShape shape = new BitSetDiscreteVoxelShape(box.getXSpan(), box.getYSpan(), box.getZSpan());
|
||||
|
||||
for (int tries = 0; tries < 6; ++tries) positions.add(Sets.newHashSet());
|
||||
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
for (BlockPos pos : Lists.newArrayList(decoratorPositions)) if (box.isInside(pos)) shape.fill(pos.getX() - box.minX(), pos.getY() - box.minY(), pos.getZ() - box.minZ());
|
||||
|
||||
for (BlockPos pos : Lists.newArrayList(trunkPositions)) {
|
||||
if (box.isInside(pos)) shape.fill(pos.getX() - box.minX(), pos.getY() - box.minY(), pos.getZ() - box.minZ());
|
||||
|
||||
for (Direction direction : Direction.values()) {
|
||||
BlockState blockState;
|
||||
mutable.setWithOffset(pos, direction);
|
||||
if (trunkPositions.contains(mutable) || !(blockState = level.getBlockState(mutable)).hasProperty(BlockStateProperties.DISTANCE)) continue;
|
||||
positions.get(0).add(mutable.immutable());
|
||||
TreeFeatureAccessor.setBlockKnownShape(level, mutable, blockState.setValue(BlockStateProperties.DISTANCE, 1));
|
||||
if (!box.isInside(mutable)) continue;
|
||||
shape.fill(mutable.getX() - box.minX(), mutable.getY() - box.minY(), mutable.getZ() - box.minZ());
|
||||
}
|
||||
}
|
||||
|
||||
for (int tries = 1; tries < 6; ++tries) {
|
||||
Set<BlockPos> trunkPos = positions.get(tries - 1);
|
||||
Set<BlockPos> foliagePos = positions.get(tries);
|
||||
for (BlockPos pos : trunkPos) {
|
||||
if (box.isInside(pos)) shape.fill(pos.getX() - box.minX(), pos.getY() - box.minY(), pos.getZ() - box.minZ());
|
||||
|
||||
for (Direction direction : Direction.values()) {
|
||||
mutable.setWithOffset(pos, direction);
|
||||
BlockState state = level.getBlockState(mutable);
|
||||
if (trunkPos.contains(mutable) || foliagePos.contains(mutable) || !state.hasProperty(BlockStateProperties.DISTANCE) || (state.getValue(BlockStateProperties.DISTANCE)) <= tries + 1) continue;
|
||||
BlockState foliage = state.setValue(BlockStateProperties.DISTANCE, tries + 1);
|
||||
TreeFeatureAccessor.setBlockKnownShape(level, mutable, foliage);
|
||||
if (box.isInside(mutable)) (shape).fill(mutable.getX() - box.minX(), mutable.getY() - box.minY(), mutable.getZ() - box.minZ());
|
||||
foliagePos.add(mutable.immutable());
|
||||
}
|
||||
}
|
||||
}
|
||||
return shape;
|
||||
|
||||
// ArrayList<Set<BlockPos>> positions = Lists.newArrayList();
|
||||
// BitSetDiscreteVoxelShape shape = new BitSetDiscreteVoxelShape(box.getXSpan(), box.getYSpan(), box.getZSpan());
|
||||
//
|
||||
// for (int tries = 0; tries < 6; ++tries) positions.add(Sets.newHashSet());
|
||||
//
|
||||
// BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
// for (BlockPos pos : Lists.newArrayList(decoratorPositions)) if (box.isInside(pos)) shape.fill(pos.getX() - box.minX(), pos.getY() - box.minY(), pos.getZ() - box.minZ());
|
||||
//
|
||||
// for (BlockPos pos : Lists.newArrayList(trunkPositions)) {
|
||||
// if (box.isInside(pos)) shape.fill(pos.getX() - box.minX(), pos.getY() - box.minY(), pos.getZ() - box.minZ());
|
||||
//
|
||||
// for (Direction direction : Direction.values()) {
|
||||
// mutable.setWithOffset(pos, direction);
|
||||
// if (trunkPositions.contains(mutable)) {
|
||||
// BlockState state = level.getBlockState(mutable);
|
||||
// if (state.hasProperty(BlockStateProperties.DISTANCE)) {
|
||||
// positions.get(0).add(mutable.immutable());
|
||||
// TreeFeatureAccessor.setBlockKnownShape(level, mutable, state.setValue(BlockStateProperties.DISTANCE, 1));
|
||||
// if (box.isInside(mutable)) shape.fill(mutable.getX() - box.minX(), mutable.getY() - box.minY(), mutable.getZ() - box.minZ());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for (int tries = 1; tries < 6; ++tries) {
|
||||
// Set<BlockPos> trunkPos = positions.get(tries - 1);
|
||||
// Set<BlockPos> foliagePos = positions.get(tries);
|
||||
// for (BlockPos pos : trunkPos) {
|
||||
// if (box.isInside(pos)) shape.fill(pos.getX() - box.minX(), pos.getY() - box.minY(), pos.getZ() - box.minZ());
|
||||
//
|
||||
// for (Direction direction : Direction.values()) {
|
||||
// mutable.setWithOffset(pos, direction);
|
||||
// if (!trunkPos.contains(mutable) && !foliagePos.contains(mutable)) {
|
||||
// BlockState state = level.getBlockState(mutable);
|
||||
// if (state.hasProperty(BlockStateProperties.DISTANCE) && state.getValue(BlockStateProperties.DISTANCE) > tries + 1) {
|
||||
// BlockState foliage = state.setValue(BlockStateProperties.DISTANCE, tries + 1);
|
||||
// TreeFeatureAccessor.setBlockKnownShape(level, mutable, foliage);
|
||||
// if (box.isInside(mutable)) (shape).fill(mutable.getX() - box.minX(), mutable.getY() - box.minY(), mutable.getZ() - box.minZ());
|
||||
// foliagePos.add(mutable.immutable());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return shape;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package com.cursedcauldron.wildbackport.common.worldgen.placers;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.RootPlacerType;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.decorator.LayerRootDecorator;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.decorator.MangroveRootPlacement;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.features.RootedTreeConfig;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.valueproviders.IntProvider;
|
||||
import net.minecraft.world.level.LevelSimulatedReader;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class MangroveRootPlacer extends RootPlacer {
|
||||
public static final Codec<MangroveRootPlacer> CODEC = RecordCodecBuilder.create(instance -> {
|
||||
return codec(instance).and(MangroveRootPlacement.CODEC.fieldOf("mangrove_root_placement").forGetter(placer -> {
|
||||
return placer.mangroveRootPlacement;
|
||||
})).apply(instance, MangroveRootPlacer::new);
|
||||
});
|
||||
private final MangroveRootPlacement mangroveRootPlacement;
|
||||
|
||||
public MangroveRootPlacer(IntProvider trunkOffsetY, BlockStateProvider rootProvider, Optional<LayerRootDecorator> aboveRootPlacement, MangroveRootPlacement mangroveRootPlacement) {
|
||||
super(trunkOffsetY, rootProvider, aboveRootPlacement);
|
||||
this.mangroveRootPlacement = mangroveRootPlacement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generate(LevelSimulatedReader level, BiConsumer<BlockPos, BlockState> replacer, Random random, BlockPos pos, BlockPos origin, RootedTreeConfig config) {
|
||||
List<BlockPos> positions = Lists.newArrayList();
|
||||
BlockPos.MutableBlockPos mutable = pos.mutable();
|
||||
|
||||
while(mutable.getY() < origin.getY()) {
|
||||
if (!this.canGrowThrough(level, mutable)) return false;
|
||||
|
||||
mutable.move(Direction.UP);
|
||||
}
|
||||
|
||||
positions.add(origin.below());
|
||||
|
||||
for(Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
BlockPos position = origin.relative(direction);
|
||||
List<BlockPos> offshootPositions = Lists.newArrayList();
|
||||
if (!this.canGrow(level, random, position, direction, origin, offshootPositions, 0)) return false;
|
||||
|
||||
positions.addAll(offshootPositions);
|
||||
positions.add(origin.relative(direction));
|
||||
}
|
||||
|
||||
for(BlockPos position : positions) this.placeRoots(level, replacer, random, position, config);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean canGrow(LevelSimulatedReader level, Random random, BlockPos pos, Direction direction, BlockPos origin, List<BlockPos> offshootPositions, int rootLength) {
|
||||
int length = this.mangroveRootPlacement.maxRootLength();
|
||||
if (rootLength != length && offshootPositions.size() <= length) {
|
||||
for(BlockPos position : this.potentialRootPositions(pos, direction, random, origin)) {
|
||||
if (this.canGrowThrough(level, position)) {
|
||||
offshootPositions.add(position);
|
||||
if (!this.canGrow(level, random, position, direction, origin, offshootPositions, rootLength + 1)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected List<BlockPos> potentialRootPositions(BlockPos pos, Direction direction, Random random, BlockPos origin) {
|
||||
BlockPos below = pos.below();
|
||||
BlockPos offset = pos.relative(direction);
|
||||
int distance = pos.distManhattan(origin);
|
||||
int rootWidth = this.mangroveRootPlacement.maxRootWidth();
|
||||
float chance = this.mangroveRootPlacement.randomSkewChance();
|
||||
if (distance > rootWidth - 3 && distance <= rootWidth) {
|
||||
return random.nextFloat() < chance ? List.of(below, offset.below()) : List.of(below);
|
||||
} else if (distance > rootWidth) {
|
||||
return List.of(below);
|
||||
} else if (random.nextFloat() < chance) {
|
||||
return List.of(below);
|
||||
} else {
|
||||
return random.nextBoolean() ? List.of(offset) : List.of(below);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canGrowThrough(LevelSimulatedReader level, BlockPos pos) {
|
||||
return super.canGrowThrough(level, pos) || level.isStateAtPosition(pos, state -> state.is(this.mangroveRootPlacement.canGrowThrough()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void placeRoots(LevelSimulatedReader level, BiConsumer<BlockPos, BlockState> replacer, Random random, BlockPos pos, RootedTreeConfig config) {
|
||||
if (level.isStateAtPosition(pos, state -> state.is(this.mangroveRootPlacement.muddyRootsIn()))) {
|
||||
BlockState state = this.mangroveRootPlacement.muddyRootsProvider().getState(random, pos);
|
||||
replacer.accept(pos, this.applyWaterlogging(level, pos, state));
|
||||
} else {
|
||||
super.placeRoots(level, replacer, random, pos, config);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RootPlacerType<?> getType() {
|
||||
return RootPlacerType.MANGROVE_ROOT_PLACER.get();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package com.cursedcauldron.wildbackport.common.worldgen.placers;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.RootPlacerType;
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.WBRegistries;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.decorator.LayerRootDecorator;
|
||||
import com.cursedcauldron.wildbackport.common.worldgen.features.RootedTreeConfig;
|
||||
import com.mojang.datafixers.Products;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.util.valueproviders.IntProvider;
|
||||
import net.minecraft.world.level.LevelSimulatedReader;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.levelgen.feature.TreeFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public abstract class RootPlacer {
|
||||
public static final Codec<RootPlacer> CODEC = WBRegistries.ROOT_PLACER_TYPES.getSecond().byNameCodec().dispatch(RootPlacer::getType, RootPlacerType::codec);
|
||||
protected final IntProvider trunkOffsetY;
|
||||
protected final BlockStateProvider rootProvider;
|
||||
protected final Optional<LayerRootDecorator> aboveRootPlacement;
|
||||
|
||||
protected static <P extends RootPlacer> Products.P3<RecordCodecBuilder.Mu<P>, IntProvider, BlockStateProvider, Optional<LayerRootDecorator>> codec(RecordCodecBuilder.Instance<P> instance) {
|
||||
return instance.group(IntProvider.CODEC.fieldOf("trunk_offset_y").forGetter(placer -> {
|
||||
return placer.trunkOffsetY;
|
||||
}), BlockStateProvider.CODEC.fieldOf("root_provider").forGetter(placer -> {
|
||||
return placer.rootProvider;
|
||||
}), LayerRootDecorator.CODEC.optionalFieldOf("above_root_placement").forGetter(placer -> {
|
||||
return placer.aboveRootPlacement;
|
||||
}));
|
||||
}
|
||||
|
||||
protected RootPlacer(IntProvider trunkOffsetY, BlockStateProvider rootProvider, Optional<LayerRootDecorator> aboveRootPlacement) {
|
||||
this.trunkOffsetY = trunkOffsetY;
|
||||
this.rootProvider = rootProvider;
|
||||
this.aboveRootPlacement = aboveRootPlacement;
|
||||
}
|
||||
|
||||
protected abstract RootPlacerType<?> getType();
|
||||
|
||||
public abstract boolean generate(LevelSimulatedReader level, BiConsumer<BlockPos, BlockState> replacer, Random random, BlockPos pos, BlockPos origin, RootedTreeConfig config);
|
||||
|
||||
protected boolean canGrowThrough(LevelSimulatedReader level, BlockPos pos) {
|
||||
return TreeFeature.validTreePos(level, pos);
|
||||
}
|
||||
|
||||
protected void placeRoots(LevelSimulatedReader level, BiConsumer<BlockPos, BlockState> replacer, Random random, BlockPos pos, RootedTreeConfig config) {
|
||||
if (this.canGrowThrough(level, pos)) {
|
||||
replacer.accept(pos, this.applyWaterlogging(level, pos, this.rootProvider.getState(random, pos)));
|
||||
if (this.aboveRootPlacement.isPresent()) {
|
||||
LayerRootDecorator decorator = this.aboveRootPlacement.get();
|
||||
BlockPos aboveRoot = pos.above();
|
||||
if (random.nextFloat() < decorator.aboveRootPlacementChance() && level.isStateAtPosition(pos, BlockBehaviour.BlockStateBase::isAir)) replacer.accept(aboveRoot, this.applyWaterlogging(level, aboveRoot, decorator.aboveRootProvider().getState(random, aboveRoot)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected BlockState applyWaterlogging(LevelSimulatedReader level, BlockPos pos, BlockState state) {
|
||||
return state.hasProperty(BlockStateProperties.WATERLOGGED) ? state.setValue(BlockStateProperties.WATERLOGGED, level.isFluidAtPosition(pos, fluid -> fluid.is(FluidTags.WATER))) : state;
|
||||
}
|
||||
|
||||
public BlockPos trunkOffset(BlockPos pos, Random random) {
|
||||
return pos.above(this.trunkOffsetY.sample(random));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package com.cursedcauldron.wildbackport.common.worldgen.placers;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.WBTrunkPlacers;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.RegistryCodecs;
|
||||
import net.minecraft.util.valueproviders.IntProvider;
|
||||
import net.minecraft.world.level.LevelSimulatedReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
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 java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
//<>
|
||||
|
||||
public class UpwardBranchingTrunk extends TrunkPlacer {
|
||||
public static final Codec<UpwardBranchingTrunk> CODEC = RecordCodecBuilder.create(instance -> {
|
||||
return trunkPlacerParts(instance).and(instance.group(IntProvider.POSITIVE_CODEC.fieldOf("extra_branch_steps").forGetter(placer -> {
|
||||
return placer.extraBranchSteps;
|
||||
}), Codec.floatRange(0.0F, 1.0F).fieldOf("place_branch_per_log_probability").forGetter(placer -> {
|
||||
return placer.placeBranchPerLogProbability;
|
||||
}), IntProvider.NON_NEGATIVE_CODEC.fieldOf("extra_branch_length").forGetter(placer -> {
|
||||
return placer.extraBranchLength;
|
||||
}), RegistryCodecs.homogeneousList(Registry.BLOCK_REGISTRY).fieldOf("can_grow_through").forGetter(placer -> {
|
||||
return placer.canGrowThrough;
|
||||
}))).apply(instance, UpwardBranchingTrunk::new);
|
||||
});
|
||||
private final IntProvider extraBranchSteps;
|
||||
private final float placeBranchPerLogProbability;
|
||||
private final IntProvider extraBranchLength;
|
||||
public final HolderSet<Block> canGrowThrough;
|
||||
|
||||
public UpwardBranchingTrunk(int baseHeight, int firstRandomHeight, int secondRandomHeight, IntProvider extraBranchSteps, float placeBranchPerLogProbability, IntProvider extraBranchLength, HolderSet<Block> canGrowThrough) {
|
||||
super(baseHeight, firstRandomHeight, secondRandomHeight);
|
||||
this.extraBranchSteps = extraBranchSteps;
|
||||
this.placeBranchPerLogProbability = placeBranchPerLogProbability;
|
||||
this.extraBranchLength = extraBranchLength;
|
||||
this.canGrowThrough = canGrowThrough;
|
||||
}
|
||||
|
||||
public List<FoliagePlacer.FoliageAttachment> placeTrunk(LevelSimulatedReader level, BiConsumer<BlockPos, BlockState> replacer, Random random, int height, BlockPos startPos, TreeConfiguration config) {
|
||||
List<FoliagePlacer.FoliageAttachment> attachments = Lists.newArrayList();
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
|
||||
for(int i = 0; i < height; ++i) {
|
||||
int yOffset = startPos.getY() + i;
|
||||
if (placeLog(level, replacer, random, mutable.set(startPos.getX(), yOffset, startPos.getZ()), config) && i < height - 1 && random.nextFloat() < this.placeBranchPerLogProbability) {
|
||||
Direction direction = Direction.Plane.HORIZONTAL.getRandomDirection(random);
|
||||
int offset = this.extraBranchLength.sample(random);
|
||||
int length = Math.max(0, offset - this.extraBranchLength.sample(random) - 1);
|
||||
int steps = this.extraBranchSteps.sample(random);
|
||||
this.placeBranch(level, replacer, random, height, config, attachments, mutable, yOffset, direction, length, steps);
|
||||
}
|
||||
|
||||
if (i == height - 1) attachments.add(new FoliagePlacer.FoliageAttachment(mutable.set(startPos.getX(), yOffset + 1, startPos.getZ()), 0, false));
|
||||
}
|
||||
|
||||
return attachments;
|
||||
}
|
||||
|
||||
private void placeBranch(LevelSimulatedReader level, BiConsumer<BlockPos, BlockState> replacer, Random random, int height, TreeConfiguration config, List<FoliagePlacer.FoliageAttachment> attachments, BlockPos.MutableBlockPos mutable, int yOffset, Direction direction, int length, int steps) {
|
||||
int y = yOffset + length;
|
||||
int x = mutable.getX();
|
||||
int z = mutable.getZ();
|
||||
|
||||
for(int l = length; l < height && steps > 0; --steps) {
|
||||
if (l >= 1) {
|
||||
int offset = yOffset + l;
|
||||
x += direction.getStepX();
|
||||
z += direction.getStepZ();
|
||||
y = offset;
|
||||
if (placeLog(level, replacer, random, mutable.set(x, offset, z), config)) y = offset + 1;
|
||||
|
||||
attachments.add(new FoliagePlacer.FoliageAttachment(mutable.immutable(), 0, false));
|
||||
}
|
||||
|
||||
++l;
|
||||
}
|
||||
|
||||
if (y - yOffset > 1) {
|
||||
BlockPos pos = new BlockPos(x, y, z);
|
||||
attachments.add(new FoliagePlacer.FoliageAttachment(pos, 0, false));
|
||||
attachments.add(new FoliagePlacer.FoliageAttachment(pos.below(2), 0, false));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TrunkPlacerType<?> type() {
|
||||
return WBTrunkPlacers.UPWARDS_BRANCHING_TRUNK.get();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.cursedcauldron.wildbackport.core.api;
|
||||
|
||||
import dev.architectury.injectables.annotations.ExpectPlatform;
|
||||
|
||||
public class Environment {
|
||||
public static boolean isForge() {
|
||||
return getPlatform() == Platform.FORGE;
|
||||
}
|
||||
|
||||
public static boolean isFabric() {
|
||||
return getPlatform() == Platform.FABRIC;
|
||||
}
|
||||
|
||||
@ExpectPlatform
|
||||
public static Platform getPlatform() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public enum Platform {
|
||||
FORGE,
|
||||
FABRIC
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.cursedcauldron.wildbackport.core.mixin.access;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(Registry.class)
|
||||
public interface RegistryAccessor {
|
||||
@Invoker
|
||||
static <T> Registry<T> callRegisterSimple(ResourceKey<? extends Registry<T>> resourceKey, Registry.RegistryBootstrap<T> registryBootstrap) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.cursedcauldron.wildbackport.core.mixin.access;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecorator;
|
||||
import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecoratorType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(TreeDecoratorType.class)
|
||||
public interface TreeDecoratorTypeAccessor {
|
||||
@Invoker("<init>")
|
||||
static <P extends TreeDecorator> TreeDecoratorType<P> createTreeDecoratorType(Codec<P> codec) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.cursedcauldron.wildbackport.core.mixin.access;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.LevelSimulatedReader;
|
||||
import net.minecraft.world.level.LevelWriter;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.TreeFeature;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(TreeFeature.class)
|
||||
public interface TreeFeatureAccessor {
|
||||
@Invoker("isVine")
|
||||
static boolean isVine(LevelSimulatedReader levelSimulatedReader, BlockPos blockPos) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Invoker("isBlockWater")
|
||||
static boolean isBlockWater(LevelSimulatedReader levelSimulatedReader, BlockPos blockPos) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Invoker("isReplaceablePlant")
|
||||
static boolean isReplaceablePlant(LevelSimulatedReader levelSimulatedReader, BlockPos blockPos) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Invoker("setBlockKnownShape")
|
||||
static void setBlockKnownShape(LevelWriter levelWriter, BlockPos blockPos, BlockState blockState) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.cursedcauldron.wildbackport.core.mixin.access;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacer;
|
||||
import net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacerType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(TrunkPlacerType.class)
|
||||
public interface TrunkPlacerTypeAccessor {
|
||||
@Invoker("<init>")
|
||||
static <P extends TrunkPlacer> TrunkPlacerType<P> createTrunkPlacerType(Codec<P> codec) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mangrove_leaves"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"#wildbackport:mangrove_logs"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mangrove_roots"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"minecraft:sculk_sensor",
|
||||
"wildbackport:sculk",
|
||||
"wildbackport:sculk_catalyst",
|
||||
"wildbackport:sculk_vein",
|
||||
"wildbackport:sculk_shrieker"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mud_bricks",
|
||||
"wildbackport:mud_brick_stairs",
|
||||
"wildbackport:mud_brick_slab",
|
||||
"wildbackport:packed_mud"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mud",
|
||||
"wildbackport:muddy_mangrove_roots"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mangrove_planks"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mud_brick_wall"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mangrove_door"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mangrove_fence"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mangrove_slab"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mangrove_stairs"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mangrove_log",
|
||||
"wildbackport:mangrove_wood",
|
||||
"wildbackport:stripped_mangrove_log",
|
||||
"wildbackport:stripped_mangrove_wood"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mud",
|
||||
"wildbackport:muddy_mangrove_roots",
|
||||
"wildbackport:mangrove_roots",
|
||||
"wildbackport:mangrove_leaves",
|
||||
"wildbackport:mangrove_log",
|
||||
"wildbackport:mangrove_propagule",
|
||||
"minecraft:moss_carpet",
|
||||
"minecraft:vine"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mud",
|
||||
"wildbackport:muddy_mangrove_roots",
|
||||
"wildbackport:mangrove_roots",
|
||||
"minecraft:moss_carpet",
|
||||
"minecraft:vine",
|
||||
"wildbackport:mangrove_propagule",
|
||||
"minecraft:snow"
|
||||
]
|
||||
}
|
|
@ -12,12 +12,16 @@
|
|||
"access.ModelPartAccessor",
|
||||
"access.PressurePlateBlockAccessor",
|
||||
"access.RecordItemAccessor",
|
||||
"access.RegistryAccessor",
|
||||
"access.SensorTypeAccessor",
|
||||
"access.SheetsAccessor",
|
||||
"access.SimpleParticleTypeAccessor",
|
||||
"access.StairBlockAccessor",
|
||||
"access.StructureTemplatePoolAccessor",
|
||||
"access.TrapDoorBlockAccessor",
|
||||
"access.TreeDecoratorTypeAccessor",
|
||||
"access.TreeFeatureAccessor",
|
||||
"access.TrunkPlacerTypeAccessor",
|
||||
"access.WalkNodeEvaluatorAccessor",
|
||||
"access.WoodButtonBlockAccessor",
|
||||
"access.WoodTypeAccessor",
|
||||
|
|
|
@ -4,5 +4,7 @@ transitive-accessible class net/minecraft/world/level/block/entity/BlockEntityTy
|
|||
transitive-accessible class net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement$Placer
|
||||
transitive-accessible class net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement$PieceState
|
||||
|
||||
transitive-accessible class net/minecraft/core/Registry$RegistryBootstrap
|
||||
|
||||
transitive-accessible method net/minecraft/client/particle/HugeExplosionParticle <init> (Lnet/minecraft/client/multiplayer/ClientLevel;DDDDLnet/minecraft/client/particle/SpriteSet;)V
|
||||
transitive-accessible method net/minecraft/world/level/block/MultifaceBlock hasFace (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/Direction;)Z
|
|
@ -0,0 +1,9 @@
|
|||
package com.cursedcauldron.wildbackport.core.api.fabric;
|
||||
|
||||
import com.cursedcauldron.wildbackport.core.api.Environment;
|
||||
|
||||
public class EnvironmentImpl {
|
||||
public static Environment.Platform getPlatform() {
|
||||
return Environment.Platform.FABRIC;
|
||||
}
|
||||
}
|
|
@ -4,5 +4,7 @@ transitive-accessible class net/minecraft/world/level/block/entity/BlockEntityTy
|
|||
transitive-accessible class net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement$Placer
|
||||
transitive-accessible class net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement$PieceState
|
||||
|
||||
transitive-accessible class net/minecraft/core/Registry$RegistryBootstrap
|
||||
|
||||
transitive-accessible method net/minecraft/client/particle/HugeExplosionParticle <init> (Lnet/minecraft/client/multiplayer/ClientLevel;DDDDLnet/minecraft/client/particle/SpriteSet;)V
|
||||
transitive-accessible method net/minecraft/world/level/block/MultifaceBlock hasFace (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/Direction;)Z
|
|
@ -0,0 +1,9 @@
|
|||
package com.cursedcauldron.wildbackport.core.api.forge;
|
||||
|
||||
import com.cursedcauldron.wildbackport.core.api.Environment;
|
||||
|
||||
public class EnvironmentImpl {
|
||||
public static Environment.Platform getPlatform() {
|
||||
return Environment.Platform.FORGE;
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ public class WildBackportForge {
|
|||
public WildBackportForge() {
|
||||
IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
EventBuses.registerModEventBus(WildBackport.MOD_ID, bus);
|
||||
bus.<FMLCommonSetupEvent>addListener(event -> CommonSetup.onPostClient());
|
||||
bus.<FMLCommonSetupEvent>addListener(event -> CommonSetup.onPostCommon());
|
||||
bus.<FMLClientSetupEvent>addListener(event -> ClientSetup.onPostClient());
|
||||
|
||||
WildBackport.bootstrap();
|
||||
|
|
Loading…
Reference in a new issue