diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/WildBackport.java b/common/src/main/java/com/cursedcauldron/wildbackport/WildBackport.java index 911a69d..c06cf21 100644 --- a/common/src/main/java/com/cursedcauldron/wildbackport/WildBackport.java +++ b/common/src/main/java/com/cursedcauldron/wildbackport/WildBackport.java @@ -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(); diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/CommonSetup.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/CommonSetup.java index 262aa81..9bbda02 100644 --- a/common/src/main/java/com/cursedcauldron/wildbackport/common/CommonSetup.java +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/CommonSetup.java @@ -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(); } } \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/blocks/MangroveTreeGrower.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/blocks/MangroveTreeGrower.java index e95c803..0744c8e 100644 --- a/common/src/main/java/com/cursedcauldron/wildbackport/common/blocks/MangroveTreeGrower.java +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/blocks/MangroveTreeGrower.java @@ -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> getConfiguredFeature(Random random, boolean bl) { - return null; + protected Holder> getConfiguredFeature(Random random, boolean bees) { + return random.nextFloat() < this.tallChance ? WBWorldGeneration.TALL_MANGROVE : WBWorldGeneration.MANGROVE; } } \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/RootPlacerType.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/RootPlacerType.java new file mode 100644 index 0000000..54ddf71 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/RootPlacerType.java @@ -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

{ + public static final CoreRegistry> PLACERS = CoreRegistry.create(WBRegistries.ROOT_PLACER_TYPES.getSecond(), WildBackport.MOD_ID); + + public static final Supplier> MANGROVE_ROOT_PLACER = PLACERS.register("mangrove_root_placer", () -> new RootPlacerType<>(MangroveRootPlacer.CODEC)); + + + private final Codec

codec; + + private RootPlacerType(Codec

codec) { + this.codec = codec; + } + + public Codec

codec() { + return this.codec; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBFeatures.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBFeatures.java new file mode 100644 index 0000000..7ffde0c --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBFeatures.java @@ -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> FEATURES = CoreRegistry.create(Registry.FEATURE, WildBackport.MOD_ID); + + public static final Supplier> TREE = FEATURES.register("tree", () -> new RootedTreeFeature(RootedTreeConfig.CODEC)); +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBRegistries.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBRegistries.java new file mode 100644 index 0000000..f16552b --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBRegistries.java @@ -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>>, Registry>> ROOT_PLACER_TYPES = create("worldgen/root_placer_type", registry -> RootPlacerType.MANGROVE_ROOT_PLACER.get()); + + private static Pair>, Registry> create(String key, Registry.RegistryBootstrap bootstrap) { + ResourceKey> resource = ResourceKey.createRegistryKey(new ResourceLocation(WildBackport.MOD_ID, key)); + Registry registry = RegistryAccessor.callRegisterSimple(resource, bootstrap); + return Pair.of(resource, registry); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBTreeDecorators.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBTreeDecorators.java new file mode 100644 index 0000000..bf432dd --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBTreeDecorators.java @@ -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> DECORATORS = CoreRegistry.create(Registry.TREE_DECORATOR_TYPES, WildBackport.MOD_ID); + + public static final Supplier> WEIGHTED_LEAVE_VINE = DECORATORS.register("leave_vine", () -> TreeDecoratorTypeAccessor.createTreeDecoratorType(WeightedLeaveVineDecorator.CODEC)); + public static final Supplier> ATTACHED_TO_LEAVES = DECORATORS.register("attached_to_leaves", () -> TreeDecoratorTypeAccessor.createTreeDecoratorType(AttachedToLeavesDecorator.CODEC)); +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBTrunkPlacers.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBTrunkPlacers.java new file mode 100644 index 0000000..2369d31 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBTrunkPlacers.java @@ -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> PLACERS = CoreRegistry.create(Registry.TRUNK_PLACER_TYPES, WildBackport.MOD_ID); + + public static final Supplier> UPWARDS_BRANCHING_TRUNK = PLACERS.register("upward_branching_trunk", () -> TrunkPlacerTypeAccessor.createTrunkPlacerType(UpwardBranchingTrunk.CODEC)); +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBWorldGeneration.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBWorldGeneration.java new file mode 100644 index 0000000..7cce869 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/registry/worldgen/WBWorldGeneration.java @@ -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> 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> 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 MANGROVE_CHECKED = place("mangrove_checked", MANGROVE, PlacementUtils.filteredByBlockSurvival(WBBlocks.MANGROVE_PROPAGULE.get())); + public static final Holder TALL_MANGROVE_CHECKED = place("tall_mangrove_checked", TALL_MANGROVE, PlacementUtils.filteredByBlockSurvival(WBBlocks.MANGROVE_PROPAGULE.get())); + + public static final Holder> 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 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 > Holder> config(String key, F feature, FC configuration) { + return BuiltinRegistries.registerExact(BuiltinRegistries.CONFIGURED_FEATURE, WildBackport.MOD_ID + ":" + key, new ConfiguredFeature<>(feature, configuration)); + } + + public static Holder place(String key, Holder> feature, PlacementModifier... placements) { + return BuiltinRegistries.registerExact(BuiltinRegistries.PLACED_FEATURE, WildBackport.MOD_ID + ":" + key, new PlacedFeature(Holder.hackyErase(feature), List.copyOf(List.of(placements)))); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/tag/WBBlockTags.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/tag/WBBlockTags.java index bb1becd..b4d7f0f 100644 --- a/common/src/main/java/com/cursedcauldron/wildbackport/common/tag/WBBlockTags.java +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/tag/WBBlockTags.java @@ -9,8 +9,14 @@ import net.minecraft.world.level.block.Block; public class WBBlockTags { public static final TagRegistry TAGS = TagRegistry.create(Registry.BLOCK, WildBackport.MOD_ID); - public static final TagKey FROG_PREFER_JUMP_TO = TAGS.create("frog_prefer_jump_to"); - public static final TagKey FROGS_SPAWNABLE_ON = TAGS.create("frogs_spawnable_on"); - public static final TagKey SCULK_REPLACEABLE = TAGS.create("sculk_replaceable"); - public static final TagKey SCULK_REPLACEABLE_WORLD_GEN = TAGS.create("sculk_replaceable_world_gen"); + // Mangrove Swamp + + public static final TagKey MANGROVE_LOGS_CAN_GROW_THROUGH = TAGS.create("mangrove_logs_can_grow_through"); + public static final TagKey MANGROVE_ROOTS_CAN_GROW_THROUGH = TAGS.create("mangrove_roots_can_grow_through"); + public static final TagKey FROG_PREFER_JUMP_TO = TAGS.create("frog_prefer_jump_to"); + public static final TagKey FROGS_SPAWNABLE_ON = TAGS.create("frogs_spawnable_on"); + + // Deep Dark + public static final TagKey SCULK_REPLACEABLE = TAGS.create("sculk_replaceable"); + public static final TagKey SCULK_REPLACEABLE_WORLD_GEN = TAGS.create("sculk_replaceable_world_gen"); } \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/AttachedToLeavesDecorator.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/AttachedToLeavesDecorator.java new file mode 100644 index 0000000..3fd8d83 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/AttachedToLeavesDecorator.java @@ -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 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 directions; + + public AttachedToLeavesDecorator(float probability, int exclusionRadiusXZ, int exclusionRadiusY, BlockStateProvider blockProvider, int requiredEmptyBlocks, List 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 replacer, Random random, List trunkPositions, List foliagePositions) { + HashSet 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(); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/LayerRootDecorator.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/LayerRootDecorator.java new file mode 100644 index 0000000..eeee00c --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/LayerRootDecorator.java @@ -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 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); + }); +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/MangroveRootPlacement.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/MangroveRootPlacement.java new file mode 100644 index 0000000..bf58e4e --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/MangroveRootPlacement.java @@ -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 canGrowThrough, HolderSet muddyRootsIn, BlockStateProvider muddyRootsProvider, int maxRootWidth, int maxRootLength, float randomSkewChance) { + public static final Codec 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); + }); +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/WeightedLeaveVineDecorator.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/WeightedLeaveVineDecorator.java new file mode 100644 index 0000000..3b2a443 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/decorator/WeightedLeaveVineDecorator.java @@ -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 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 replacer, Random random, List trunkPositions, List 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 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(); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/features/RootedTreeConfig.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/features/RootedTreeConfig.java new file mode 100644 index 0000000..5127c76 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/features/RootedTreeConfig.java @@ -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 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; + + protected RootedTreeConfig(BlockStateProvider trunkProvider, TrunkPlacer trunkPlacer, BlockStateProvider foliageProvider, FoliagePlacer foliagePlacer, Optional rootPlacer, BlockStateProvider dirtProvider, FeatureSize minimumSize, List 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; + private BlockStateProvider dirtProvider; + private final FeatureSize minimumSize; + private List decorators = ImmutableList.of(); + private boolean ignoreVines; + private boolean forceDirt; + + public Builder(BlockStateProvider trunkProvider, TrunkPlacer trunkPlacer, BlockStateProvider foliageProvider, FoliagePlacer foliagePlacer, Optional 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 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); + } + } +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/features/RootedTreeFeature.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/features/RootedTreeFeature.java new file mode 100644 index 0000000..fa56b5a --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/features/RootedTreeFeature.java @@ -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 { + public RootedTreeFeature(Codec codec) { + super(codec); + } + + private boolean generate(WorldGenLevel level, Random random, BlockPos pos, BiConsumer rootPlacerReplacer, BiConsumer trunkPlacerReplacer, BiConsumer 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 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 context) { + WorldGenLevel level = context.level(); + Random random = context.random(); + BlockPos pos = context.origin(); + RootedTreeConfig config = context.config(); + HashSet rootPos = Sets.newHashSet(); + HashSet trunkPos = Sets.newHashSet(); + HashSet foliagePos = Sets.newHashSet(); + HashSet decoratorPos = Sets.newHashSet(); + BiConsumer rootReplacer = (position, state) -> { + rootPos.add(position.immutable()); + level.setBlock(position, state, 19); + }; + BiConsumer trunkReplacer = (position, state) -> { + trunkPos.add(position.immutable()); + level.setBlock(position, state, 19); + }; + BiConsumer foliageReplacer = (position, state) -> { + foliagePos.add(position.immutable()); + level.setBlock(position, state, 19); + }; + BiConsumer 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 rootPositions = Lists.newArrayList(rootPos); + ArrayList trunkPositions = Lists.newArrayList(trunkPos); + ArrayList 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 trunkPositions, Set decoratorPositions) { + ArrayList> 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 trunkPos = positions.get(tries - 1); + Set 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> 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 trunkPos = positions.get(tries - 1); +// Set 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; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/placers/MangroveRootPlacer.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/placers/MangroveRootPlacer.java new file mode 100644 index 0000000..6420101 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/placers/MangroveRootPlacer.java @@ -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 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 aboveRootPlacement, MangroveRootPlacement mangroveRootPlacement) { + super(trunkOffsetY, rootProvider, aboveRootPlacement); + this.mangroveRootPlacement = mangroveRootPlacement; + } + + @Override + public boolean generate(LevelSimulatedReader level, BiConsumer replacer, Random random, BlockPos pos, BlockPos origin, RootedTreeConfig config) { + List 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 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 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 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 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(); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/placers/RootPlacer.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/placers/RootPlacer.java new file mode 100644 index 0000000..c36e52d --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/placers/RootPlacer.java @@ -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 CODEC = WBRegistries.ROOT_PLACER_TYPES.getSecond().byNameCodec().dispatch(RootPlacer::getType, RootPlacerType::codec); + protected final IntProvider trunkOffsetY; + protected final BlockStateProvider rootProvider; + protected final Optional aboveRootPlacement; + + protected static

Products.P3, IntProvider, BlockStateProvider, Optional> codec(RecordCodecBuilder.Instance

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 aboveRootPlacement) { + this.trunkOffsetY = trunkOffsetY; + this.rootProvider = rootProvider; + this.aboveRootPlacement = aboveRootPlacement; + } + + protected abstract RootPlacerType getType(); + + public abstract boolean generate(LevelSimulatedReader level, BiConsumer 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 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)); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/placers/UpwardBranchingTrunk.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/placers/UpwardBranchingTrunk.java new file mode 100644 index 0000000..e8b7ee0 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/worldgen/placers/UpwardBranchingTrunk.java @@ -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 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 canGrowThrough; + + public UpwardBranchingTrunk(int baseHeight, int firstRandomHeight, int secondRandomHeight, IntProvider extraBranchSteps, float placeBranchPerLogProbability, IntProvider extraBranchLength, HolderSet canGrowThrough) { + super(baseHeight, firstRandomHeight, secondRandomHeight); + this.extraBranchSteps = extraBranchSteps; + this.placeBranchPerLogProbability = placeBranchPerLogProbability; + this.extraBranchLength = extraBranchLength; + this.canGrowThrough = canGrowThrough; + } + + public List placeTrunk(LevelSimulatedReader level, BiConsumer replacer, Random random, int height, BlockPos startPos, TreeConfiguration config) { + List 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 replacer, Random random, int height, TreeConfiguration config, List 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(); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/core/api/Environment.java b/common/src/main/java/com/cursedcauldron/wildbackport/core/api/Environment.java new file mode 100644 index 0000000..ac5553f --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/core/api/Environment.java @@ -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 + } +} \ No newline at end of file diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/RegistryAccessor.java b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/RegistryAccessor.java new file mode 100644 index 0000000..79c58e9 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/RegistryAccessor.java @@ -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 Registry callRegisterSimple(ResourceKey> resourceKey, Registry.RegistryBootstrap registryBootstrap) { + throw new UnsupportedOperationException(); + } +} diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/TreeDecoratorTypeAccessor.java b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/TreeDecoratorTypeAccessor.java new file mode 100644 index 0000000..7e12e90 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/TreeDecoratorTypeAccessor.java @@ -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("") + static

TreeDecoratorType

createTreeDecoratorType(Codec

codec) { + throw new UnsupportedOperationException(); + } +} diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/TreeFeatureAccessor.java b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/TreeFeatureAccessor.java new file mode 100644 index 0000000..aabca95 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/TreeFeatureAccessor.java @@ -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(); + } +} diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/TrunkPlacerTypeAccessor.java b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/TrunkPlacerTypeAccessor.java new file mode 100644 index 0000000..e2c6a67 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/access/TrunkPlacerTypeAccessor.java @@ -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("") + static

TrunkPlacerType

createTrunkPlacerType(Codec

codec) { + throw new UnsupportedOperationException(); + } +} diff --git a/common/src/main/resources/data/minecraft/tags/blocks/leaves.json b/common/src/main/resources/data/minecraft/tags/blocks/leaves.json new file mode 100644 index 0000000..e00969d --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/leaves.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "wildbackport:mangrove_leaves" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/minecraft/tags/blocks/logs_that_burn.json b/common/src/main/resources/data/minecraft/tags/blocks/logs_that_burn.json new file mode 100644 index 0000000..8771410 --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/logs_that_burn.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "#wildbackport:mangrove_logs" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json b/common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json new file mode 100644 index 0000000..9d71f29 --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "wildbackport:mangrove_roots" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/minecraft/tags/blocks/mineable/hoe.json b/common/src/main/resources/data/minecraft/tags/blocks/mineable/hoe.json new file mode 100644 index 0000000..a3c7989 --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/mineable/hoe.json @@ -0,0 +1,10 @@ +{ + "replace": false, + "values": [ + "minecraft:sculk_sensor", + "wildbackport:sculk", + "wildbackport:sculk_catalyst", + "wildbackport:sculk_vein", + "wildbackport:sculk_shrieker" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/common/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json new file mode 100644 index 0000000..6c29af2 --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -0,0 +1,9 @@ +{ + "replace": false, + "values": [ + "wildbackport:mud_bricks", + "wildbackport:mud_brick_stairs", + "wildbackport:mud_brick_slab", + "wildbackport:packed_mud" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/minecraft/tags/blocks/mineable/shovel.json b/common/src/main/resources/data/minecraft/tags/blocks/mineable/shovel.json new file mode 100644 index 0000000..353ed7e --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/mineable/shovel.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "wildbackport:mud", + "wildbackport:muddy_mangrove_roots" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/minecraft/tags/blocks/planks.json b/common/src/main/resources/data/minecraft/tags/blocks/planks.json new file mode 100644 index 0000000..c62d7d6 --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/planks.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "wildbackport:mangrove_planks" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/minecraft/tags/blocks/walls.json b/common/src/main/resources/data/minecraft/tags/blocks/walls.json new file mode 100644 index 0000000..af2cfaa --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/walls.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "wildbackport:mud_brick_wall" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/minecraft/tags/blocks/wooden_doors.json b/common/src/main/resources/data/minecraft/tags/blocks/wooden_doors.json new file mode 100644 index 0000000..fbe3af3 --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/wooden_doors.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "wildbackport:mangrove_door" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/minecraft/tags/blocks/wooden_fences.json b/common/src/main/resources/data/minecraft/tags/blocks/wooden_fences.json new file mode 100644 index 0000000..be90b5c --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/wooden_fences.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "wildbackport:mangrove_fence" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/minecraft/tags/blocks/wooden_slabs.json b/common/src/main/resources/data/minecraft/tags/blocks/wooden_slabs.json new file mode 100644 index 0000000..2715336 --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/wooden_slabs.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "wildbackport:mangrove_slab" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/minecraft/tags/blocks/wooden_stairs.json b/common/src/main/resources/data/minecraft/tags/blocks/wooden_stairs.json new file mode 100644 index 0000000..3d20251 --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/blocks/wooden_stairs.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "wildbackport:mangrove_stairs" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/wildbackport/tags/blocks/mangrove_logs.json b/common/src/main/resources/data/wildbackport/tags/blocks/mangrove_logs.json new file mode 100644 index 0000000..5357192 --- /dev/null +++ b/common/src/main/resources/data/wildbackport/tags/blocks/mangrove_logs.json @@ -0,0 +1,9 @@ +{ + "replace": false, + "values": [ + "wildbackport:mangrove_log", + "wildbackport:mangrove_wood", + "wildbackport:stripped_mangrove_log", + "wildbackport:stripped_mangrove_wood" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/wildbackport/tags/blocks/mangrove_logs_can_grow_through.json b/common/src/main/resources/data/wildbackport/tags/blocks/mangrove_logs_can_grow_through.json new file mode 100644 index 0000000..d588a67 --- /dev/null +++ b/common/src/main/resources/data/wildbackport/tags/blocks/mangrove_logs_can_grow_through.json @@ -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" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/wildbackport/tags/blocks/mangrove_roots_can_grow_through.json b/common/src/main/resources/data/wildbackport/tags/blocks/mangrove_roots_can_grow_through.json new file mode 100644 index 0000000..d380be2 --- /dev/null +++ b/common/src/main/resources/data/wildbackport/tags/blocks/mangrove_roots_can_grow_through.json @@ -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" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/wildbackport-common.mixins.json b/common/src/main/resources/wildbackport-common.mixins.json index fcee79c..e05c625 100644 --- a/common/src/main/resources/wildbackport-common.mixins.json +++ b/common/src/main/resources/wildbackport-common.mixins.json @@ -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", diff --git a/common/src/main/resources/wildbackport.accesswidener b/common/src/main/resources/wildbackport.accesswidener index 7e49688..42dc488 100644 --- a/common/src/main/resources/wildbackport.accesswidener +++ b/common/src/main/resources/wildbackport.accesswidener @@ -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 (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 \ No newline at end of file diff --git a/fabric/src/main/java/com/cursedcauldron/wildbackport/core/api/fabric/EnvironmentImpl.java b/fabric/src/main/java/com/cursedcauldron/wildbackport/core/api/fabric/EnvironmentImpl.java new file mode 100644 index 0000000..c491b50 --- /dev/null +++ b/fabric/src/main/java/com/cursedcauldron/wildbackport/core/api/fabric/EnvironmentImpl.java @@ -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; + } +} \ No newline at end of file diff --git a/fabric/src/main/resources/wildbackport.accesswidener b/fabric/src/main/resources/wildbackport.accesswidener index 7e49688..42dc488 100644 --- a/fabric/src/main/resources/wildbackport.accesswidener +++ b/fabric/src/main/resources/wildbackport.accesswidener @@ -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 (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 \ No newline at end of file diff --git a/forge/src/main/java/com/cursedcauldron/wildbackport/core/api/forge/EnvironmentImpl.java b/forge/src/main/java/com/cursedcauldron/wildbackport/core/api/forge/EnvironmentImpl.java new file mode 100644 index 0000000..08f3c2b --- /dev/null +++ b/forge/src/main/java/com/cursedcauldron/wildbackport/core/api/forge/EnvironmentImpl.java @@ -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; + } +} \ No newline at end of file diff --git a/forge/src/main/java/com/cursedcauldron/wildbackport/forge/WildBackportForge.java b/forge/src/main/java/com/cursedcauldron/wildbackport/forge/WildBackportForge.java index 0d6ea8b..37a146d 100644 --- a/forge/src/main/java/com/cursedcauldron/wildbackport/forge/WildBackportForge.java +++ b/forge/src/main/java/com/cursedcauldron/wildbackport/forge/WildBackportForge.java @@ -17,7 +17,7 @@ public class WildBackportForge { public WildBackportForge() { IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); EventBuses.registerModEventBus(WildBackport.MOD_ID, bus); - bus.addListener(event -> CommonSetup.onPostClient()); + bus.addListener(event -> CommonSetup.onPostCommon()); bus.addListener(event -> ClientSetup.onPostClient()); WildBackport.bootstrap();