diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/NaturalCloudBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/NaturalCloudBlock.java index 2d7325dc..cc176942 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/NaturalCloudBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/NaturalCloudBlock.java @@ -6,6 +6,8 @@ import org.jetbrains.annotations.Nullable; import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.SpawnGroup; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.registry.tag.ItemTags; @@ -16,6 +18,7 @@ import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; import net.minecraft.world.World; public class NaturalCloudBlock extends PoreousCloudBlock { @@ -25,10 +28,23 @@ public class NaturalCloudBlock extends PoreousCloudBlock { public NaturalCloudBlock(Settings settings, boolean meltable, @Nullable Supplier soggyBlock, Supplier compactedBlock) { - super(settings.nonOpaque(), meltable, soggyBlock); + super(settings.nonOpaque().allowsSpawning((state, world, pos, type) -> { + return type == EntityType.PHANTOM || type == EntityType.PARROT || type.getSpawnGroup() == SpawnGroup.AMBIENT; + }), meltable, soggyBlock); this.compactedBlock = compactedBlock; } + @Override + @Deprecated + public float getAmbientOcclusionLightLevel(BlockState state, BlockView world, BlockPos pos) { + return 0.9F; + } + + @Override + public boolean isTransparent(BlockState state, BlockView world, BlockPos pos) { + return true; + } + @Override public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { ItemStack stack = player.getStackInHand(hand); diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinHeightmap.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinHeightmap.java new file mode 100644 index 00000000..99da4dde --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinHeightmap.java @@ -0,0 +1,21 @@ +package com.minelittlepony.unicopia.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import com.minelittlepony.unicopia.block.cloud.CloudLike; + +import net.minecraft.block.BlockState; +import net.minecraft.world.Heightmap; + +@Mixin(Heightmap.class) +abstract class MixinHeightmap { + @Inject(method = "method_16682", at = @At("HEAD"), cancellable = true) + private static void excludeCloudsFromWorldSurfaceHeightMap(BlockState state, CallbackInfoReturnable info) { + if (state.getBlock() instanceof CloudLike) { + info.setReturnValue(false); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java b/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java index 5100d075..2c8d1903 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java @@ -7,6 +7,7 @@ import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.block.ShellsBlock; import com.minelittlepony.unicopia.block.UBlocks; import com.minelittlepony.unicopia.server.world.gen.CaveCarvingStructureProcessor; +import com.minelittlepony.unicopia.server.world.gen.CloudCarver; import com.minelittlepony.unicopia.server.world.gen.OverworldBiomeSelectionCallback; import com.minelittlepony.unicopia.server.world.gen.SurfaceGrowthStructureProcessor; import com.minelittlepony.unicopia.util.registry.DynamicRegistry; @@ -38,6 +39,9 @@ import net.minecraft.world.biome.OverworldBiomeCreator; import net.minecraft.world.biome.SpawnSettings; import net.minecraft.world.gen.GenerationStep; import net.minecraft.world.gen.blockpredicate.BlockPredicate; +import net.minecraft.world.gen.carver.Carver; +import net.minecraft.world.gen.carver.CaveCarverConfig; +import net.minecraft.world.gen.carver.ConfiguredCarver; import net.minecraft.world.gen.feature.ConfiguredFeatures; import net.minecraft.world.gen.feature.DefaultBiomeFeatures; import net.minecraft.world.gen.feature.Feature; @@ -126,6 +130,9 @@ public interface UWorldGen { StructureProcessorType SURFACE_GROWTH_STRUCTURE_PROCESSOR = Registry.register(Registries.STRUCTURE_PROCESSOR, Unicopia.id("surface_growth"), () -> SurfaceGrowthStructureProcessor.CODEC); StructureProcessorType CAVE_CARVING_STRUCTURE_PROCESSOR = Registry.register(Registries.STRUCTURE_PROCESSOR, Unicopia.id("cave_carving"), () -> CaveCarvingStructureProcessor.CODEC); + RegistryKey> OVERWORLD_CLOUD_CARVER_CONFIG = RegistryKey.of(RegistryKeys.CONFIGURED_CARVER, Unicopia.id("overworld_cloud_carver")); + Carver CLOUR_CARVER = Registry.register(Registries.CARVER, Unicopia.id("cloud"), new CloudCarver(CaveCarverConfig.CAVE_CODEC)); + @SafeVarargs static T applyAll(T t, Consumer ...consumers) { for (Consumer consumer : consumers) { @@ -142,6 +149,7 @@ public interface UWorldGen { .or(BiomeSelectors.tag(BiomeTags.IS_RIVER)) .or(BiomeSelectors.includeByKey(BiomeKeys.STONY_SHORE)) ), GenerationStep.Feature.VEGETAL_DECORATION, SHELLS_PLACED_FEATURE); + BiomeModifications.addCarver(BiomeSelectors.foundInOverworld(), GenerationStep.Carver.AIR, OVERWORLD_CLOUD_CARVER_CONFIG); UTreeGen.bootstrap(); OverworldBiomeSelectionCallback.EVENT.register(context -> { diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/gen/CloudCarver.java b/src/main/java/com/minelittlepony/unicopia/server/world/gen/CloudCarver.java new file mode 100644 index 00000000..21356298 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/gen/CloudCarver.java @@ -0,0 +1,142 @@ +package com.minelittlepony.unicopia.server.world.gen; + +import java.util.function.Function; + +import com.minelittlepony.unicopia.block.UBlocks; +import com.mojang.serialization.Codec; +import net.minecraft.block.BlockState; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.gen.carver.Carver; +import net.minecraft.world.gen.carver.CarverContext; +import net.minecraft.world.gen.carver.CarvingMask; +import net.minecraft.world.gen.carver.CaveCarver; +import net.minecraft.world.gen.carver.CaveCarverConfig; +import net.minecraft.world.gen.chunk.AquiferSampler; +import net.minecraft.world.gen.densityfunction.DensityFunction.NoisePos; + +public class CloudCarver extends CaveCarver { + + private Random random; + + public CloudCarver(Codec codec) { + super(codec); + } + + @Override + protected int getMaxCaveCount() { + return 15; + } + + @Override + protected float getTunnelSystemWidth(Random random) { + return (random.nextFloat() * 2.0F + random.nextFloat()) * 2.0F; + } + + @Override + protected double getTunnelSystemHeightWidthRatio() { + return 0.5; + } + + @Override + public boolean carve( + CarverContext context, + CaveCarverConfig config, + Chunk chunk, + Function> function, + Random random, + AquiferSampler sampler, + ChunkPos chunkPos, + CarvingMask carvingMask + ) { + this.random = random; + return super.carve(context, config, chunk, function, random, new AquiferSampler() { + @Override + public BlockState apply(NoisePos pos, double density) { + BlockState state = sampler.apply(pos, density); + return state != null && state.isAir() ? UBlocks.CLOUD.getDefaultState() : state; + } + + @Override + public boolean needsFluidTick() { + return sampler.needsFluidTick(); + } + + }, chunkPos, carvingMask); + } + + @Override + protected void carveCave( + CarverContext context, + CaveCarverConfig config, + Chunk chunk, + Function> posToBiome, + AquiferSampler aquiferSampler, + double x, + double y, + double z, + float xScale, + double yScale, + CarvingMask mask, + Carver.SkipPredicate skipPredicate + ) { + if (random == null) { + return; + } + int maxY = context.getMinY() + context.getHeight(); + + int bubbleCount = 10 + random.nextInt(12); + for (int i = 0; i < bubbleCount; i++) { + double width = 1.5 * xScale + random.nextTriangular(3, 2); + double height = Math.min(width * yScale * (1 + random.nextFloat() * 2) + MathHelper.sin((float) (Math.PI / 2)) * xScale, maxY - y); + double bubbleX = x + (random.nextFloat() * 2 - 1) * width; + double bubbleZ = z + (random.nextFloat() * 2 - 1) * width; + carveRegion(context, config, chunk, posToBiome, aquiferSampler, bubbleX + 1.0, y, bubbleZ, width, height, mask, skipPredicate); + } + } + + @Override + protected void carveTunnels( + CarverContext context, + CaveCarverConfig config, + Chunk chunk, + Function> posToBiome, + long seed, + AquiferSampler aquiferSampler, + double x, + double y, + double z, + double horizontalScale, + double verticalScale, + float w, + float yaw, + float pitch, + int branchStartIndex, + int branchCount, + double yawPitchRatio, + CarvingMask mask, + Carver.SkipPredicate skipPredicate + ) { + if (random == null) { + return; + } + int maxY = context.getMinY() + context.getHeight(); + int bubbleCount = 10 + random.nextInt(12); + for (int i = 0; i < bubbleCount; i++) { + double width = /*1.5 + MathHelper.sin((float) (Math.PI / 2)) * xScale +*/ 1.5 * horizontalScale + random.nextInt(3) + w; + double height = width * (1 + random.nextFloat() * 2) * verticalScale * 0.2; + double bubbleX = x + (random.nextFloat() * 2 - 1) * width * 1.5; + double bubbleZ = z + (random.nextFloat() * 2 - 1) * width * 1.5; + double bubbleY = y + random.nextFloat() * height * 0.5; + if (bubbleY + height < maxY) { + carveRegion(context, config, chunk, posToBiome, aquiferSampler, bubbleX, bubbleY, bubbleZ, width, height, mask, skipPredicate); + } + } + //super.carveTunnels(context, config, chunk, posToBiome, seed, aquiferSampler, x, y, z, horizontalScale, verticalScale, w, yaw, pitch, branchStartIndex, branchCount, yawPitchRatio, mask, skipPredicate); + } +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/worldgen/configured_carver/overworld_cloud_carver.json b/src/main/resources/data/unicopia/worldgen/configured_carver/overworld_cloud_carver.json new file mode 100644 index 00000000..b7543372 --- /dev/null +++ b/src/main/resources/data/unicopia/worldgen/configured_carver/overworld_cloud_carver.json @@ -0,0 +1,26 @@ +{ + "type": "unicopia:cloud", + "config": { + "probability": 0.05, + "y": { + "type": "minecraft:uniform", + "min_inclusive": { + "absolute": 240 + }, + "max_inclusive": { + "absolute": 600 + } + }, + "yScale": 0.15, + "lava_level": { + "above_bottom": 8 + }, + "replaceable": "minecraft:air", + "horizontal_radius_multiplier": 3.7, + "vertical_radius_multiplier": 2.8, + "floor_level": { + "type": "minecraft:constant", + "value": 0 + } + } +} diff --git a/src/main/resources/unicopia.mixin.json b/src/main/resources/unicopia.mixin.json index be3b67d5..3079ef57 100644 --- a/src/main/resources/unicopia.mixin.json +++ b/src/main/resources/unicopia.mixin.json @@ -28,6 +28,7 @@ "MixinFallingBlockEntity", "MixinFlowableFluid", "MixinGuardianTargetPredicate", + "MixinHeightmap", "MixinItem", "MixinItemEntity", "MixinItemStack",