From 1a3655d244056eb182a21e4f95312dd00176d167 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 9 Sep 2023 14:32:27 +0100 Subject: [PATCH] Pineapple plants now generate in jungle biomes --- .../com/minelittlepony/unicopia/Unicopia.java | 4 +- .../unicopia/block/PineappleCropBlock.java | 15 ++- .../unicopia/block/UBlocks.java | 6 +- .../server/world/FeatureRegistry.java | 58 ++++++++++++ .../server/world/PineapplePlantFeature.java | 94 +++++++++++++++++++ .../unicopia/server/world/UWorldGen.java | 33 +++++++ 6 files changed, 205 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/server/world/FeatureRegistry.java create mode 100644 src/main/java/com/minelittlepony/unicopia/server/world/PineapplePlantFeature.java create mode 100644 src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java diff --git a/src/main/java/com/minelittlepony/unicopia/Unicopia.java b/src/main/java/com/minelittlepony/unicopia/Unicopia.java index a714e97a..4ecf28b8 100644 --- a/src/main/java/com/minelittlepony/unicopia/Unicopia.java +++ b/src/main/java/com/minelittlepony/unicopia/Unicopia.java @@ -32,7 +32,7 @@ import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; import com.minelittlepony.unicopia.server.world.NocturnalSleepManager; import com.minelittlepony.unicopia.server.world.UGameRules; -import com.minelittlepony.unicopia.server.world.UTreeGen; +import com.minelittlepony.unicopia.server.world.UWorldGen; import com.minelittlepony.unicopia.server.world.WeatherConditions; import com.minelittlepony.unicopia.server.world.ZapAppleStageStore; import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; @@ -95,7 +95,7 @@ public class Unicopia implements ModInitializer { SpellType.bootstrap(); Abilities.bootstrap(); UScreenHandlers.bootstrap(); - UTreeGen.bootstrap(); + UWorldGen.bootstrap(); UGameRules.bootstrap(); UDamageTypes.bootstrap(); } diff --git a/src/main/java/com/minelittlepony/unicopia/block/PineappleCropBlock.java b/src/main/java/com/minelittlepony/unicopia/block/PineappleCropBlock.java index 3df5e75d..7f9c147b 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/PineappleCropBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/PineappleCropBlock.java @@ -1,11 +1,13 @@ package com.minelittlepony.unicopia.block; +import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.seasons.FertilizableUtil; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.CropBlock; import net.minecraft.block.enums.BlockHalf; +import net.minecraft.item.ItemStack; import net.minecraft.registry.tag.BlockTags; import net.minecraft.server.world.ServerWorld; import net.minecraft.state.StateManager; @@ -21,14 +23,23 @@ import net.minecraft.world.WorldAccess; import net.minecraft.world.WorldView; public class PineappleCropBlock extends CropBlock { - private static final EnumProperty HALF = Properties.BLOCK_HALF; - private static final BooleanProperty WILD = BooleanProperty.of("wild"); + public static final EnumProperty HALF = Properties.BLOCK_HALF; + public static final BooleanProperty WILD = BooleanProperty.of("wild"); public PineappleCropBlock(Settings settings) { super(settings); setDefaultState(getDefaultState().with(HALF, BlockHalf.BOTTOM).with(WILD, false)); } + + @Override + public ItemStack getPickStack(BlockView world, BlockPos pos, BlockState state) { + if (state.get(HALF) == BlockHalf.TOP) { + return UItems.PINEAPPLE.getDefaultStack(); + } + return UItems.PINEAPPLE_CROWN.getDefaultStack(); + } + @Override protected boolean canPlantOnTop(BlockState floor, BlockView world, BlockPos pos) { return floor.isOf(this) || super.canPlantOnTop(floor, world, pos); diff --git a/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java b/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java index bb82d012..06a2d72a 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java +++ b/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java @@ -72,7 +72,7 @@ public interface UBlocks { Block PALM_LEAVES = register("palm_leaves", BlockConstructionUtils.createLeavesBlock(BlockSoundGroup.GRASS), ItemGroups.BUILDING_BLOCKS); Block BANANAS = register("bananas", new FruitBlock(Settings.create().mapColor(MapColor.YELLOW).sounds(BlockSoundGroup.WOOD).noCollision().ticksRandomly().breakInstantly().pistonBehavior(PistonBehavior.DESTROY), Direction.DOWN, PALM_LEAVES, VoxelShapes.fullCube())); - Block PINEAPPLE = register("pineapple", new PineappleCropBlock(Settings.create().sounds(BlockSoundGroup.GRASS).noCollision().breakInstantly().pistonBehavior(PistonBehavior.DESTROY))); + PineappleCropBlock PINEAPPLE = register("pineapple", new PineappleCropBlock(Settings.create().sounds(BlockSoundGroup.GRASS).noCollision().breakInstantly().pistonBehavior(PistonBehavior.DESTROY))); Block MANGO_LEAVES = register("mango_leaves", new FruitBearingBlock(FabricBlockSettings.copy(Blocks.JUNGLE_LEAVES), 0xCCFFAA00, @@ -151,6 +151,10 @@ public interface UBlocks { TRANSLUCENT_BLOCKS.add(WEATHER_VANE); TintedBlock.REGISTRY.add(PALM_LEAVES); + FlammableBlockRegistry.getDefaultInstance().add(GREEN_APPLE_LEAVES, 30, 60); + FlammableBlockRegistry.getDefaultInstance().add(SWEET_APPLE_LEAVES, 30, 60); + FlammableBlockRegistry.getDefaultInstance().add(SOUR_APPLE_LEAVES, 30, 60); + FlammableBlockRegistry.getDefaultInstance().add(MANGO_LEAVES, 30, 60); FlammableBlockRegistry.getDefaultInstance().add(PALM_LEAVES, 30, 60); FlammableBlockRegistry.getDefaultInstance().add(PALM_LOG, 5, 5); FlammableBlockRegistry.getDefaultInstance().add(PALM_WOOD, 5, 5); diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/FeatureRegistry.java b/src/main/java/com/minelittlepony/unicopia/server/world/FeatureRegistry.java new file mode 100644 index 00000000..1a4b6dcb --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/FeatureRegistry.java @@ -0,0 +1,58 @@ +package com.minelittlepony.unicopia.server.world; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +import java.util.function.Function; + +import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback; +import net.minecraft.registry.*; +import net.minecraft.world.gen.feature.*; +import net.minecraft.world.gen.placementmodifier.PlacementModifier; +import net.minecraft.registry.entry.*; +import net.minecraft.util.Identifier; + +class FeatureRegistry { + private static final List CONFIGURED_FEATURES = new ArrayList<>(); + private static final List PLACED_FEATURES = new ArrayList<>(); + static { + DynamicRegistrySetupCallback.EVENT.register(registries -> { + registries.getOptional(RegistryKeys.CONFIGURED_FEATURE).ifPresent(registry -> { + CONFIGURED_FEATURES.forEach(entry -> { + Registry.register(registry, entry.key(), entry.factory().get()); + }); + }); + registries.getOptional(RegistryKeys.PLACED_FEATURE).ifPresent(registry -> { + var lookup = registries.getOptional(RegistryKeys.CONFIGURED_FEATURE).orElseThrow(); + PLACED_FEATURES.forEach(entry -> { + Registry.register(registry, entry.key(), entry.factory().apply(lookup.getEntry(entry.configuration()).orElseThrow())); + }); + }); + }); + } + + public static , FC extends FeatureConfig> RegistryKey registerPlaceableFeature( + Identifier id, + F feature, FC featureConfig, + List placementModifiers) { + + var configurationKey = RegistryKey.of(RegistryKeys.CONFIGURED_FEATURE, id); + var placementKey = RegistryKey.of(RegistryKeys.PLACED_FEATURE, id); + + CONFIGURED_FEATURES.add(new ConfiguredEntry(configurationKey, () -> new ConfiguredFeature<>(feature, featureConfig))); + PLACED_FEATURES.add(new PlacedEntry(placementKey, configurationKey, config -> new PlacedFeature(config, placementModifiers))); + return placementKey; + } + + record ConfiguredEntry ( + RegistryKey> key, + Supplier> factory + ) {} + + record PlacedEntry ( + RegistryKey key, + RegistryKey> configuration, + Function>, PlacedFeature> factory + ) {} +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/PineapplePlantFeature.java b/src/main/java/com/minelittlepony/unicopia/server/world/PineapplePlantFeature.java new file mode 100644 index 00000000..26267fcd --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/PineapplePlantFeature.java @@ -0,0 +1,94 @@ +package com.minelittlepony.unicopia.server.world; + +import com.minelittlepony.unicopia.block.PineappleCropBlock; +import com.minelittlepony.unicopia.block.UBlocks; +import com.mojang.serialization.Codec; + +import net.minecraft.block.enums.BlockHalf; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.StructureWorldAccess; +import net.minecraft.world.gen.feature.Feature; +import net.minecraft.world.gen.feature.FeatureConfig; +import net.minecraft.world.gen.feature.util.FeatureContext; + +public class PineapplePlantFeature extends Feature { + + public PineapplePlantFeature() { + super(Config.CODEC); + } + + @Override + public boolean generate(FeatureContext context) { + final StructureWorldAccess world = context.getWorld(); + + final Random random = context.getRandom(); + + int xOffset = 3; + int zOffset = 3; + + BlockPos.Mutable mutablePos = context.getOrigin().mutableCopy(); + boolean succeeded = false; + for (BlockPos position : BlockPos.iterateOutwards(context.getOrigin(), xOffset, 0, zOffset)) { + if (random.nextFloat() < 0.5) { + continue; + } + + findTerrainLevel(world, mutablePos.set(position)); + + if (world.isOutOfHeightLimit(mutablePos) + || (!world.isAir(mutablePos) && !isReplaceable(world, mutablePos)) + || !isSoil(world, mutablePos.move(Direction.DOWN))) { + continue; + } + + mutablePos.move(Direction.UP); + + int maxAge = UBlocks.PINEAPPLE.getMaxAge(); + int age = random.nextBetween(maxAge - 3, maxAge); + + succeeded = true; + setBlockState(world, mutablePos, UBlocks.PINEAPPLE.withAge(age).with(PineappleCropBlock.WILD, true)); + + if (age >= maxAge) { + mutablePos.move(Direction.UP); + + if (isReplaceable(world, mutablePos)) { + setBlockState(world, mutablePos, UBlocks.PINEAPPLE + .withAge(random.nextBetween(maxAge / 2, maxAge)) + .with(PineappleCropBlock.HALF, BlockHalf.TOP) + .with(PineappleCropBlock.WILD, true)); + } + } + } + + return succeeded; + } + + static void findTerrainLevel(StructureWorldAccess world, BlockPos.Mutable mutablePos) { + if (isReplaceable(world, mutablePos)) { + do { + mutablePos.move(Direction.DOWN); + } while (isReplaceable(world, mutablePos) && !world.isOutOfHeightLimit(mutablePos)); + + mutablePos.move(Direction.UP); + } + + if (!isReplaceable(world, mutablePos)) { + do { + mutablePos.move(Direction.UP); + } while (!isReplaceable(world, mutablePos) && !world.isOutOfHeightLimit(mutablePos)); + } + } + + static boolean isReplaceable(StructureWorldAccess world, BlockPos pos) { + return (world.isAir(pos) || world.getBlockState(pos).isIn(BlockTags.REPLACEABLE_BY_TREES)) && world.getBlockState(pos).getFluidState().isEmpty(); + } + + public static class Config implements FeatureConfig { + public static final Config INSTANCE = new Config(); + public static final Codec CODEC = Codec.unit(INSTANCE); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java b/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java new file mode 100644 index 00000000..cd1ae14f --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java @@ -0,0 +1,33 @@ +package com.minelittlepony.unicopia.server.world; + +import java.util.List; + +import com.minelittlepony.unicopia.Unicopia; + +import net.fabricmc.fabric.api.biome.v1.BiomeModifications; +import net.fabricmc.fabric.api.biome.v1.BiomeSelectors; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.tag.BiomeTags; +import net.minecraft.world.gen.GenerationStep; +import net.minecraft.world.gen.feature.PlacedFeature; +import net.minecraft.world.gen.feature.PlacedFeatures; +import net.minecraft.world.gen.placementmodifier.BiomePlacementModifier; +import net.minecraft.world.gen.placementmodifier.RarityFilterPlacementModifier; +import net.minecraft.world.gen.placementmodifier.SquarePlacementModifier; + +public interface UWorldGen { + PineapplePlantFeature PINEAPPLE_PLANT_FEATURE = Registry.register(Registries.FEATURE, Unicopia.id("pineapple_plant"), new PineapplePlantFeature()); + RegistryKey PINEAPPLE_PLANT_PLACED_FEATURE = FeatureRegistry.registerPlaceableFeature(Unicopia.id("pineapple_plant"), PINEAPPLE_PLANT_FEATURE, PineapplePlantFeature.Config.INSTANCE, List.of( + RarityFilterPlacementModifier.of(100), + SquarePlacementModifier.of(), + PlacedFeatures.MOTION_BLOCKING_HEIGHTMAP, + BiomePlacementModifier.of() + )); + + static void bootstrap() { + BiomeModifications.addFeature(BiomeSelectors.tag(BiomeTags.IS_JUNGLE), GenerationStep.Feature.VEGETAL_DECORATION, PINEAPPLE_PLANT_PLACED_FEATURE); + UTreeGen.bootstrap(); + } +}