From ae9e16d51f1bdea1a26101c743d2a91f135957b1 Mon Sep 17 00:00:00 2001 From: Zepalesque <60141811+Zepalesque@users.noreply.github.com> Date: Sat, 1 Jun 2024 18:28:20 -0400 Subject: [PATCH] feat: stuffs --- gradle.properties | 2 +- src/main/java/net/zepalesque/redux/Redux.java | 8 +- .../redux/client/audio/ReduxMusic.java | 12 +++ .../redux/config/DataSerializableConfig.java | 8 +- .../zepalesque/redux/config/ReduxConfig.java | 12 +-- .../net/zepalesque/redux/data/ReduxTags.java | 9 +- .../redux/data/gen/ReduxRegistrySets.java | 5 ++ .../data/gen/tags/ReduxBiomeTagsGen.java | 23 +++++ .../data/resource/ReduxBiomeModifiers.java | 52 ++++++++++++ .../redux/data/resource/ReduxConditions.java | 5 ++ .../data/resource/ReduxDensityFunctions.java | 55 ++++++++++++ .../data/resource/ReduxFeatureConfig.java | 22 ++++- .../redux/data/resource/ReduxPlacements.java | 40 +++++++++ .../world/feature/gen/CloudbedFeature.java | 85 +++++++++++++++++++ .../world/feature/gen/ReduxFeatures.java | 17 ++++ 15 files changed, 343 insertions(+), 12 deletions(-) create mode 100644 src/main/java/net/zepalesque/redux/client/audio/ReduxMusic.java create mode 100644 src/main/java/net/zepalesque/redux/data/gen/tags/ReduxBiomeTagsGen.java create mode 100644 src/main/java/net/zepalesque/redux/data/resource/ReduxBiomeModifiers.java create mode 100644 src/main/java/net/zepalesque/redux/data/resource/ReduxDensityFunctions.java create mode 100644 src/main/java/net/zepalesque/redux/world/feature/gen/CloudbedFeature.java create mode 100644 src/main/java/net/zepalesque/redux/world/feature/gen/ReduxFeatures.java diff --git a/gradle.properties b/gradle.properties index 870cd5838..82353d426 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,7 +19,7 @@ aether_version=1.20.4-1.4.1-neoforge nitrogen_version=1.20.4-1.1.4-neoforge cumulus_version=1.20.4-1.0.1-neoforge curios_version=7.3.4 -zenith_version=1.0.35 +zenith_version=1.0.36 aeroblender_version=5271794 terrablender_version=1.20.4-3.3.0.12 terrablender_version_minimum=1.20.4-3.3.0.0 diff --git a/src/main/java/net/zepalesque/redux/Redux.java b/src/main/java/net/zepalesque/redux/Redux.java index 81fcdf1de..c816fc611 100644 --- a/src/main/java/net/zepalesque/redux/Redux.java +++ b/src/main/java/net/zepalesque/redux/Redux.java @@ -48,12 +48,14 @@ import net.zepalesque.redux.data.gen.ReduxLootGen; import net.zepalesque.redux.data.gen.ReduxRecipeGen; import net.zepalesque.redux.data.gen.ReduxRegistrySets; +import net.zepalesque.redux.data.gen.tags.ReduxBiomeTagsGen; import net.zepalesque.redux.data.gen.tags.ReduxBlockTagsGen; import net.zepalesque.redux.data.gen.tags.ReduxItemTagsGen; import net.zepalesque.redux.entity.ReduxEntities; import net.zepalesque.redux.item.ReduxItems; import net.zepalesque.redux.tile.ReduxTiles; import net.zepalesque.redux.world.biome.tint.ReduxBiomeTints; +import net.zepalesque.redux.world.feature.gen.ReduxFeatures; import net.zepalesque.zenith.api.biometint.BiomeTints; import net.zepalesque.zenith.api.blockset.AbstractStoneSet; import net.zepalesque.zenith.api.blockset.AbstractWoodSet; @@ -95,11 +97,12 @@ public Redux(IEventBus bus, Dist dist) { ReduxEntities.ENTITIES.register(bus); ReduxTiles.TILES.register(bus); ReduxBiomeTints.TINTS.register(bus); + ReduxFeatures.FEATURES.register(bus); ReduxConfigHandler.setup(bus); - ConfigCondition.registerSerializer("redux_server", new ConfigSerializer(ReduxConfig.SERVER::serialize, ReduxConfig.SERVER::deserialize)); - ConfigCondition.registerSerializer("redux_common", new ConfigSerializer(ReduxConfig.COMMON::serialize, ReduxConfig.COMMON::deserialize)); + ConfigCondition.registerSerializer(ReduxConfig.SERVER.serializerID(), new ConfigSerializer(ReduxConfig.SERVER::serialize, ReduxConfig.SERVER::deserialize)); + ConfigCondition.registerSerializer(ReduxConfig.COMMON.serializerID(), new ConfigSerializer(ReduxConfig.COMMON::serialize, ReduxConfig.COMMON::deserialize)); } private void commonSetup(final FMLCommonSetupEvent event) { @@ -135,6 +138,7 @@ private void dataSetup(GatherDataEvent event) { ReduxBlockTagsGen blockTags = new ReduxBlockTagsGen(packOutput, lookupProvider, fileHelper); generator.addProvider(event.includeServer(), blockTags); generator.addProvider(event.includeServer(), new ReduxItemTagsGen(packOutput, lookupProvider, blockTags.contentsGetter(), fileHelper)); + generator.addProvider(event.includeServer(), new ReduxBiomeTagsGen(packOutput, lookupProvider, fileHelper)); // pack.mcmeta generator.addProvider(true, new PackMetadataGenerator(packOutput).add(PackMetadataSection.TYPE, new PackMetadataSection( diff --git a/src/main/java/net/zepalesque/redux/client/audio/ReduxMusic.java b/src/main/java/net/zepalesque/redux/client/audio/ReduxMusic.java new file mode 100644 index 000000000..446fd203b --- /dev/null +++ b/src/main/java/net/zepalesque/redux/client/audio/ReduxMusic.java @@ -0,0 +1,12 @@ +package net.zepalesque.redux.client.audio; + +import com.aetherteam.aether.client.AetherSoundEvents; +import net.minecraft.sounds.Music; + +public class ReduxMusic { + public static final Music DEFAULT_AETHER_MUSIC = new Music(AetherSoundEvents.MUSIC_AETHER.getHolder().orElseThrow(), 12000, 24000, true); +// public static final Music REDUX_MENU = new Music(ReduxSoundEvents.REDUX_MENU.getHolder().orElseThrow(), 0, 0, true); + + public static final int MUSIC_MIN = 1200; + public static final int MUSIC_MAX = 3600; +} diff --git a/src/main/java/net/zepalesque/redux/config/DataSerializableConfig.java b/src/main/java/net/zepalesque/redux/config/DataSerializableConfig.java index 2244eb1db..c2f72c934 100644 --- a/src/main/java/net/zepalesque/redux/config/DataSerializableConfig.java +++ b/src/main/java/net/zepalesque/redux/config/DataSerializableConfig.java @@ -9,9 +9,11 @@ public class DataSerializableConfig { protected final ModConfigSpec spec; + protected final String id; - public DataSerializableConfig(ModConfigSpec spec) { + public DataSerializableConfig(ModConfigSpec spec, String id) { this.spec = spec; + this.id = id; } public String serialize(ModConfigSpec.ConfigValue config) { @@ -31,4 +33,8 @@ public ModConfigSpec.ConfigValue deserialize(String string) { public ModConfigSpec spec() { return spec; } + + public String serializerID() { + return this.id; + } } diff --git a/src/main/java/net/zepalesque/redux/config/ReduxConfig.java b/src/main/java/net/zepalesque/redux/config/ReduxConfig.java index 404ed3a34..6b81cecd8 100644 --- a/src/main/java/net/zepalesque/redux/config/ReduxConfig.java +++ b/src/main/java/net/zepalesque/redux/config/ReduxConfig.java @@ -7,14 +7,14 @@ public class ReduxConfig { public static class Server extends DataSerializableConfig { - public final ModConfigSpec.ConfigValue placeholder; + public final ModConfigSpec.ConfigValue redux_sky_colors; public Server(ModConfigSpec.Builder builder) { - super(SERVER_SPEC); + super(SERVER_SPEC, "redux_server"); builder.push("TODO"); - placeholder = builder - .comment("Temporary placeholder config, used") - .define("Placeholder Config", true); + redux_sky_colors = builder + .comment("Use Redux's alternative sky colors for the Aether") + .define("Redux Sky Colors", true); builder.pop(); } } @@ -24,7 +24,7 @@ public static class Common extends DataSerializableConfig { public final ModConfigSpec.ConfigValue placeholder; public Common(ModConfigSpec.Builder builder) { - super(COMMON_SPEC); + super(COMMON_SPEC, "redux_common"); builder.push("TODO"); placeholder = builder .comment("Temporary placeholder config, used") diff --git a/src/main/java/net/zepalesque/redux/data/ReduxTags.java b/src/main/java/net/zepalesque/redux/data/ReduxTags.java index f3c365b6b..dd107ced3 100644 --- a/src/main/java/net/zepalesque/redux/data/ReduxTags.java +++ b/src/main/java/net/zepalesque/redux/data/ReduxTags.java @@ -44,7 +44,14 @@ private static TagKey> tag(String name) { } public static class Biomes { - + + public static final TagKey MODIFY_MUSIC = tag("should_modify_music"); + // TODO: Biome-dependent skies + public static final TagKey MODIFY_SKY_COLOR = tag("should_modify_sky_color"); + + public static final TagKey HAS_SENTRITE = tag("has_sentrite"); + public static final TagKey HAS_CLOUDBED = tag("has_cloudbed"); + private static TagKey tag(String name) { return TagKey.create(Registries.BIOME, Redux.loc(name)); } diff --git a/src/main/java/net/zepalesque/redux/data/gen/ReduxRegistrySets.java b/src/main/java/net/zepalesque/redux/data/gen/ReduxRegistrySets.java index bbf473b3e..f9d45dd3c 100644 --- a/src/main/java/net/zepalesque/redux/data/gen/ReduxRegistrySets.java +++ b/src/main/java/net/zepalesque/redux/data/gen/ReduxRegistrySets.java @@ -10,7 +10,9 @@ import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider; import net.neoforged.neoforge.registries.NeoForgeRegistries; import net.zepalesque.redux.Redux; +import net.zepalesque.redux.data.resource.ReduxBiomeModifiers; import net.zepalesque.redux.data.resource.ReduxConditions; +import net.zepalesque.redux.data.resource.ReduxDensityFunctions; import net.zepalesque.redux.data.resource.ReduxFeatureConfig; import net.zepalesque.redux.data.resource.ReduxPlacements; import net.zepalesque.zenith.Zenith; @@ -25,6 +27,9 @@ public class ReduxRegistrySets extends DatapackBuiltinEntriesProvider { public static final RegistrySetBuilder BUILDER = new RegistrySetBuilder() .add(Registries.CONFIGURED_FEATURE, ReduxFeatureConfig::bootstrap) + .add(Registries.PLACED_FEATURE, ReduxPlacements::bootstrap) + .add(Registries.DENSITY_FUNCTION, ReduxDensityFunctions::bootstrap) + .add(NeoForgeRegistries.Keys.BIOME_MODIFIERS, ReduxBiomeModifiers::bootstrap) .add(Zenith.Keys.CONDITION, ReduxConditions::bootstrap); public ReduxRegistrySets(PackOutput output, CompletableFuture registries, String modid, String... otherIds) { diff --git a/src/main/java/net/zepalesque/redux/data/gen/tags/ReduxBiomeTagsGen.java b/src/main/java/net/zepalesque/redux/data/gen/tags/ReduxBiomeTagsGen.java new file mode 100644 index 000000000..0d3573e9f --- /dev/null +++ b/src/main/java/net/zepalesque/redux/data/gen/tags/ReduxBiomeTagsGen.java @@ -0,0 +1,23 @@ +package net.zepalesque.redux.data.gen.tags; + +import net.minecraft.core.HolderLookup; +import net.minecraft.data.PackOutput; +import net.minecraft.data.tags.BiomeTagsProvider; +import net.neoforged.neoforge.common.data.ExistingFileHelper; +import net.zepalesque.redux.Redux; + +import javax.annotation.Nullable; +import java.util.concurrent.CompletableFuture; + +public class ReduxBiomeTagsGen extends BiomeTagsProvider { + + public ReduxBiomeTagsGen(PackOutput output, CompletableFuture registries, @Nullable ExistingFileHelper helper) { + super(output, registries, Redux.MODID, helper); + } + + @SuppressWarnings("unchecked") + @Override + public void addTags(HolderLookup.Provider provider) { + + } +} diff --git a/src/main/java/net/zepalesque/redux/data/resource/ReduxBiomeModifiers.java b/src/main/java/net/zepalesque/redux/data/resource/ReduxBiomeModifiers.java new file mode 100644 index 000000000..660ff88dd --- /dev/null +++ b/src/main/java/net/zepalesque/redux/data/resource/ReduxBiomeModifiers.java @@ -0,0 +1,52 @@ +package net.zepalesque.redux.data.resource; + +import net.minecraft.core.HolderGetter; +import net.minecraft.core.HolderSet; +import net.minecraft.core.registries.Registries; +import net.minecraft.data.worldgen.BootstapContext; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import net.neoforged.neoforge.common.world.BiomeModifier; +import net.neoforged.neoforge.common.world.BiomeModifiers; +import net.neoforged.neoforge.registries.NeoForgeRegistries; +import net.zepalesque.redux.Redux; +import net.zepalesque.redux.client.audio.ReduxMusic; +import net.zepalesque.redux.data.ReduxTags; +import net.zepalesque.zenith.Zenith; +import net.zepalesque.zenith.api.condition.Condition; +import net.zepalesque.zenith.util.codec.CodecPredicates; +import net.zepalesque.zenith.world.biome.modifier.MusicModifier; +import net.zepalesque.zenith.world.biome.modifier.SkyModifier; + +import java.util.Optional; + +public class ReduxBiomeModifiers { + public static final ResourceKey ADD_CLOUDBED = createKey("add_cloudbed"); + public static final ResourceKey SKY_COLOR_AETHER = createKey("modify_sky_color"); + public static final ResourceKey MUSIC_MODIFY = createKey("modify_music"); + + private static ResourceKey createKey(String name) { + return ResourceKey.create(NeoForgeRegistries.Keys.BIOME_MODIFIERS, Redux.loc(name)); + } + + public static void bootstrap(BootstapContext context) { + HolderGetter biomes = context.lookup(Registries.BIOME); + HolderGetter> carvers = context.lookup(Registries.CONFIGURED_CARVER); + HolderGetter features = context.lookup(Registries.PLACED_FEATURE); + HolderGetter> conditions = context.lookup(Zenith.Keys.CONDITION); + + context.register(ADD_CLOUDBED, new BiomeModifiers.AddFeaturesBiomeModifier( + biomes.getOrThrow(ReduxTags.Biomes.HAS_CLOUDBED), HolderSet.direct(features.getOrThrow(ReduxPlacements.CLOUDBED)), + GenerationStep.Decoration.RAW_GENERATION)); + + context.register(SKY_COLOR_AETHER, new SkyModifier(biomes.getOrThrow(ReduxTags.Biomes.MODIFY_SKY_COLOR), + CodecPredicates.DualInt.of(12632319, 9671612), 0x9FA4DD, 0xBEC4E5, Optional.of(conditions.get(ReduxConditions.SKY_COLORS).orElseThrow()))); + + // TODO: MusicPredicate, with optional fields for each field of the Music class + context.register(MUSIC_MODIFY, new MusicModifier(biomes.getOrThrow(ReduxTags.Biomes.MODIFY_MUSIC), + Optional.empty(), Optional.of(CodecPredicates.DualInt.of(ReduxMusic.MUSIC_MIN, ReduxMusic.MUSIC_MAX)), Optional.of(false), Optional.empty(), Optional.empty(), Optional.empty())); + } +} diff --git a/src/main/java/net/zepalesque/redux/data/resource/ReduxConditions.java b/src/main/java/net/zepalesque/redux/data/resource/ReduxConditions.java index 91997f263..ecc31ea38 100644 --- a/src/main/java/net/zepalesque/redux/data/resource/ReduxConditions.java +++ b/src/main/java/net/zepalesque/redux/data/resource/ReduxConditions.java @@ -2,8 +2,10 @@ import net.minecraft.data.worldgen.BootstapContext; import net.minecraft.resources.ResourceKey; +import net.zepalesque.redux.config.ReduxConfig; import net.zepalesque.zenith.Zenith; import net.zepalesque.zenith.api.condition.Condition; +import net.zepalesque.zenith.api.condition.ConfigCondition; import net.zepalesque.zenith.api.condition.ModLoadedCondition; public class ReduxConditions { @@ -13,11 +15,14 @@ public class ReduxConditions { public static final ResourceKey> LOST = createKey("lost_content"); public static final ResourceKey> ANCIENT = createKey("ancient_aether"); + public static final ResourceKey> SKY_COLORS = createKey("sky_colors"); + public static void bootstrap(BootstapContext> context) { context.register(DEEP, new ModLoadedCondition("deep_aether")); context.register(GENESIS, new ModLoadedCondition("aether_genesis")); context.register(LOST, new ModLoadedCondition("lost_aether_content")); context.register(ANCIENT, new ModLoadedCondition("ancient_aether")); + context.register(SKY_COLORS, new ConfigCondition(ReduxConfig.SERVER.serializerID(), ReduxConfig.SERVER.redux_sky_colors)); } private static ResourceKey> createKey(String name) { diff --git a/src/main/java/net/zepalesque/redux/data/resource/ReduxDensityFunctions.java b/src/main/java/net/zepalesque/redux/data/resource/ReduxDensityFunctions.java new file mode 100644 index 000000000..02821094f --- /dev/null +++ b/src/main/java/net/zepalesque/redux/data/resource/ReduxDensityFunctions.java @@ -0,0 +1,55 @@ +package net.zepalesque.redux.data.resource; + +import net.minecraft.core.HolderGetter; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.data.worldgen.BootstapContext; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.levelgen.DensityFunction; +import net.minecraft.world.level.levelgen.DensityFunctions; +import net.minecraft.world.level.levelgen.synth.BlendedNoise; +import net.minecraft.world.level.levelgen.synth.NormalNoise; +import net.zepalesque.redux.Redux; +import net.zepalesque.zenith.world.density.PerlinNoiseFunction; + +import java.util.Optional; + +public class ReduxDensityFunctions { + + public static final ResourceKey CLOUDBED_NOISE = createKey("cloudbed_noise"); + public static final ResourceKey CLOUDBED_Y_OFFSET = createKey("cloudbed_y_offset"); + + public static void bootstrap(BootstapContext context) { + context.register(CLOUDBED_NOISE, DensityFunctions.mul(new PerlinNoiseFunction(new NormalNoise.NoiseParameters(0, 1, 1, 1, 1, 1, 1), 0.01D, 0.0D, 42), DensityFunctions.constant(1.5D))); + + context.register(CLOUDBED_Y_OFFSET, DensityFunctions.mul(new PerlinNoiseFunction(new NormalNoise.NoiseParameters(0, 1, 1), 0.005D, 0.0D, 95), DensityFunctions.constant(1.5D))); + + } + + private static ResourceKey createKey(String name) { + return ResourceKey.create(Registries.DENSITY_FUNCTION, new ResourceLocation(Redux.MODID, name)); + } + + public static DensityFunction get(HolderGetter densityFunctions, ResourceKey key) { + return new DensityFunctions.HolderHolder(densityFunctions.getOrThrow(key)); + } + + public static DensityFunction get(RegistryAccess access, ResourceKey key) { + Optional> optional = access.lookup(Registries.DENSITY_FUNCTION); + if (optional.isPresent()) { + HolderLookup.RegistryLookup lookup = optional.get(); + return lookup.getOrThrow(key).value(); + + } else { + throw new NullPointerException("Optional value is not present!"); + } + } + + public static DensityFunction get(Level level, ResourceKey key) { + return level.registryAccess().registryOrThrow(Registries.DENSITY_FUNCTION).getOrThrow(key); + } + +} \ No newline at end of file diff --git a/src/main/java/net/zepalesque/redux/data/resource/ReduxFeatureConfig.java b/src/main/java/net/zepalesque/redux/data/resource/ReduxFeatureConfig.java index bff4234e6..d7a2091eb 100644 --- a/src/main/java/net/zepalesque/redux/data/resource/ReduxFeatureConfig.java +++ b/src/main/java/net/zepalesque/redux/data/resource/ReduxFeatureConfig.java @@ -9,10 +9,13 @@ import net.minecraft.core.registries.Registries; import net.minecraft.data.worldgen.BootstapContext; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.util.random.SimpleWeightedRandomList; import net.minecraft.util.valueproviders.ConstantInt; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.DensityFunction; +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.configurations.FeatureConfiguration; @@ -21,8 +24,11 @@ import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider; import net.minecraft.world.level.levelgen.feature.stateproviders.WeightedStateProvider; import net.neoforged.neoforge.registries.DeferredHolder; +import net.zepalesque.redux.Redux; import net.zepalesque.redux.block.state.ReduxStates; import net.zepalesque.redux.blockset.wood.ReduxWoodSets; +import net.zepalesque.redux.world.feature.gen.CloudbedFeature; +import net.zepalesque.redux.world.feature.gen.ReduxFeatures; import java.util.function.Supplier; @@ -30,8 +36,11 @@ public class ReduxFeatureConfig { public static final ResourceKey> CRYSTAL_TREE_OVERRIDE = AetherConfiguredFeatures.CRYSTAL_TREE_CONFIGURATION; + public static final ResourceKey> CLOUDBED = createKey("cloudbed"); + public static void bootstrap(BootstapContext> context) { - HolderGetter> configuredFeatures = context.lookup(Registries.CONFIGURED_FEATURE); + HolderGetter> configs = context.lookup(Registries.CONFIGURED_FEATURE); + HolderGetter functions = context.lookup(Registries.DENSITY_FUNCTION); register(context, CRYSTAL_TREE_OVERRIDE, Feature.TREE, new TreeConfiguration.TreeConfigurationBuilder( prov(ReduxWoodSets.CRYSTAL.log()), @@ -39,12 +48,23 @@ public static void bootstrap(BootstapContext> context) { new WeightedStateProvider(new SimpleWeightedRandomList.Builder().add(AetherFeatureStates.CRYSTAL_LEAVES, 4).add(AetherFeatureStates.CRYSTAL_FRUIT_LEAVES, 1).build()), new CrystalFoliagePlacer(ConstantInt.of(0), ConstantInt.of(0), ConstantInt.of(6)), new TwoLayersFeatureSize(1, 0, 1)).ignoreVines().build()); + + register(context, CLOUDBED, ReduxFeatures.CLOUDBED.get(), + new CloudbedFeature.Config( + prov(AetherFeatureStates.COLD_AERCLOUD), + BlockPredicate.ONLY_IN_AIR_PREDICATE, + 16, ReduxDensityFunctions.get(functions, ReduxDensityFunctions.CLOUDBED_NOISE), + 10, ReduxDensityFunctions.get(functions, ReduxDensityFunctions.CLOUDBED_Y_OFFSET), 10)); } private static > void register(BootstapContext> context, ResourceKey> key, F feature, FC configuration) { context.register(key, new ConfiguredFeature<>(feature, configuration)); } + private static ResourceKey> createKey(String name) { + return ResourceKey.create(Registries.CONFIGURED_FEATURE, new ResourceLocation(Redux.MODID, name)); + } + private static String name(DeferredHolder reg) { return reg.getId().getPath(); } diff --git a/src/main/java/net/zepalesque/redux/data/resource/ReduxPlacements.java b/src/main/java/net/zepalesque/redux/data/resource/ReduxPlacements.java index d28c294f4..47b0e51ca 100644 --- a/src/main/java/net/zepalesque/redux/data/resource/ReduxPlacements.java +++ b/src/main/java/net/zepalesque/redux/data/resource/ReduxPlacements.java @@ -1,14 +1,17 @@ package net.zepalesque.redux.data.resource; +import com.aetherteam.aether.Aether; import com.aetherteam.aether.block.AetherBlockStateProperties; import com.aetherteam.aether.data.resources.AetherFeatureStates; import com.aetherteam.aether.data.resources.registries.AetherConfiguredFeatures; import com.aetherteam.aether.world.foliageplacer.CrystalFoliagePlacer; import com.aetherteam.aether.world.trunkplacer.CrystalTreeTrunkPlacer; +import net.minecraft.core.Holder; import net.minecraft.core.HolderGetter; import net.minecraft.core.registries.Registries; import net.minecraft.data.worldgen.BootstapContext; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.util.random.SimpleWeightedRandomList; import net.minecraft.util.valueproviders.ConstantInt; import net.minecraft.world.level.block.Block; @@ -20,12 +23,49 @@ import net.minecraft.world.level.levelgen.feature.featuresize.TwoLayersFeatureSize; import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider; import net.minecraft.world.level.levelgen.feature.stateproviders.WeightedStateProvider; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import net.minecraft.world.level.levelgen.placement.PlacementModifier; import net.neoforged.neoforge.registries.DeferredHolder; +import net.zepalesque.redux.Redux; import net.zepalesque.redux.block.state.ReduxStates; import net.zepalesque.redux.blockset.wood.ReduxWoodSets; +import java.util.List; import java.util.function.Supplier; public class ReduxPlacements { + public static final ResourceKey CLOUDBED = copyKey(ReduxFeatureConfig.CLOUDBED); + + public static void bootstrap(BootstapContext context) { + HolderGetter> configs = context.lookup(Registries.CONFIGURED_FEATURE); + + register(context, CLOUDBED, configs.getOrThrow(ReduxFeatureConfig.CLOUDBED)); + } + + private static void register(BootstapContext context, ResourceKey key, Holder> configuration, List modifiers) { + context.register(key, new PlacedFeature(configuration, List.copyOf(modifiers))); + } + + private static void register(BootstapContext context, ResourceKey key, Holder> configuration, PlacementModifier... modifiers) { + register(context, key, configuration, List.of(modifiers)); + } + + private static ResourceKey createKey(String name) { + return ResourceKey.create(Registries.PLACED_FEATURE, new ResourceLocation(Redux.MODID, name)); + } + + private static ResourceKey copyKey(ResourceKey> configFeat) { + return createKey(configFeat.location().getPath()); + } + + private static ResourceKey aetherKey(String name) { + return ResourceKey.create(Registries.PLACED_FEATURE, new ResourceLocation(Aether.MODID, name)); + } + + private static String name(DeferredHolder reg) { + return reg.getId().getPath(); + } + + } diff --git a/src/main/java/net/zepalesque/redux/world/feature/gen/CloudbedFeature.java b/src/main/java/net/zepalesque/redux/world/feature/gen/CloudbedFeature.java new file mode 100644 index 000000000..1c6b98591 --- /dev/null +++ b/src/main/java/net/zepalesque/redux/world/feature/gen/CloudbedFeature.java @@ -0,0 +1,85 @@ +package net.zepalesque.redux.world.feature.gen; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.levelgen.DensityFunction; +import net.minecraft.world.level.levelgen.XoroshiroRandomSource; +import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate; +import net.minecraft.world.level.levelgen.feature.Feature; +import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; +import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration; +import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider; +import net.minecraft.world.level.levelgen.synth.PerlinSimplexNoise; + +import java.util.List; + +public class CloudbedFeature extends Feature { + + public CloudbedFeature(Codec codec) { + super(codec); + } + + @Override + public boolean place(FeaturePlaceContext context) { + + Config config = context.config(); + + DensityFunction cloudNoise = config.cloudNoise(); + DensityFunction yOffsetNoise = config.yOffset(); + + // This should be placed, once per chunk + int chunkX = context.origin().getX() - (context.origin().getX() % 16); + int chunkZ = context.origin().getZ() - (context.origin().getZ() % 16); + // Place blocks across the entire chunk + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + // calculate new coords based on the for loops' values + int xCoord = chunkX + x; + int zCoord = chunkZ + z; + // The main cloud noise is what is used for the distinction of gaps and non-gaps + double cloudCalc = cloudNoise.compute(new DensityFunction.SinglePointContext(xCoord, config.yLevel(), zCoord)); + // A Y offset is then calculated and applied using a second, smoother and larger noise + double offsetCalc = yOffsetNoise.compute(new DensityFunction.SinglePointContext(xCoord, config.yLevel(), zCoord)); + float realOffset = cosineInterp((float) Mth.inverseLerp(offsetCalc, -0.5, 0.5), 0F, (float) config.maxYOffset()); + // We don't need to, and shouldn't, generate anything if the cloud noise value is below zero + if (cloudCalc >= 0) { + // Interpolate for some extra smoothness + float realCloud = cosineInterp((float) Mth.clamp(cloudCalc, 0, 1), 0, 1); + // Calculate how many blocks up from the main y offset plane should be generated + float blocksUp = Mth.lerp(realCloud, 0F, (float) config.cloudRadius()) + realOffset; + // Calculate how many blocks down from the main y offset plane should be generated + float blocksDown = Mth.lerp(realCloud, 0F, (float) config.cloudRadius() - 1F) - realOffset; + // Floor these values and then place the blocks + for (int i = Mth.floor(-blocksDown); i <= Mth.floor(blocksUp); i++) { + int y = Mth.clamp(config.yLevel() + i, context.level().getMinBuildHeight(), context.level().getMaxBuildHeight()); + BlockPos pos = new BlockPos(xCoord, y, zCoord); + if (config.predicate().test(context.level(), pos)) { + this.setBlock(context.level(), pos, config.block().getState(context.random(), pos)); + } + } + } + } + } + return false; + } + + private static float cosineInterp(float progress, float start, float end) { + return (-Mth.cos((float) (Math.PI * progress)) + 1F) * 0.5F * (end - start) + start; + } + + public record Config(BlockStateProvider block, BlockPredicate predicate, int yLevel, DensityFunction cloudNoise, double cloudRadius, DensityFunction yOffset, double maxYOffset) implements FeatureConfiguration { + public static final Codec CODEC = RecordCodecBuilder.create( + (builder) -> builder.group( + BlockStateProvider.CODEC.fieldOf("block").forGetter(Config::block), + BlockPredicate.CODEC.fieldOf("predicate").forGetter(Config::predicate), + Codec.INT.fieldOf("y_level").forGetter(Config::yLevel), + DensityFunction.HOLDER_HELPER_CODEC.fieldOf("cloud_noise").forGetter(Config::cloudNoise), + Codec.DOUBLE.fieldOf("cloud_radius").forGetter(Config::cloudRadius), + DensityFunction.HOLDER_HELPER_CODEC.fieldOf("offset_noise").forGetter(Config::yOffset), + Codec.DOUBLE.fieldOf("offset_max").forGetter(Config::maxYOffset) + + ).apply(builder, Config::new)); + } +} diff --git a/src/main/java/net/zepalesque/redux/world/feature/gen/ReduxFeatures.java b/src/main/java/net/zepalesque/redux/world/feature/gen/ReduxFeatures.java new file mode 100644 index 000000000..c4c4e5f7a --- /dev/null +++ b/src/main/java/net/zepalesque/redux/world/feature/gen/ReduxFeatures.java @@ -0,0 +1,17 @@ +package net.zepalesque.redux.world.feature.gen; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.level.levelgen.feature.Feature; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.zepalesque.redux.Redux; +import net.zepalesque.zenith.Zenith; +import net.zepalesque.zenith.world.feature.gen.TestAtBlockFeature; +import net.zepalesque.zenith.world.feature.gen.TestBelowBlockFeature; +import net.zepalesque.zenith.world.feature.gen.config.PredicateStateConfig; + +public class ReduxFeatures { + public static final DeferredRegister> FEATURES = DeferredRegister.create(BuiltInRegistries.FEATURE, Redux.MODID); + + public static DeferredHolder, Feature> CLOUDBED = FEATURES.register("cloudbed", () -> new CloudbedFeature(CloudbedFeature.Config.CODEC)); +}