Skip to content

Commit

Permalink
feat: 'Extendable State List'
Browse files Browse the repository at this point in the history
  • Loading branch information
Zepalesque committed Jan 2, 2025
1 parent 45362df commit df79ead
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 2 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ org.gradle.debug=false


# Version
mod_version=1.2.05
mod_version=1.2.06

# Mod
mod_id=zenith
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package net.zepalesque.zenith.api.extendablestate;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.RandomSource;
import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.zepalesque.zenith.core.registry.StateLists;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class ExtendableStateList {
private final int weightForDefaults, weightForOthers, totalWeight;
private final SimpleWeightedRandomList<BlockState> defaults;
private final List<Entry> entries = new ArrayList<>();

public ExtendableStateList(int weightForDefaults, int weightForOthers, SimpleWeightedRandomList<BlockState> defaults) {
this.weightForDefaults = weightForDefaults;
this.weightForOthers = weightForOthers;
this.defaults = defaults;

this.totalWeight = weightForDefaults + weightForOthers;
}

public BlockState calculate(RandomSource random, WorldGenLevel level, BlockPos pos) {
if (this.totalWeight == 0) return Blocks.AIR.defaultBlockState();

int i = random.nextInt(totalWeight);
if (i < this.weightForDefaults) return calculateDefaults(random, level, pos);
else return calculateOther(random, level, pos);

}

private BlockState calculateDefaults(RandomSource random, WorldGenLevel level, BlockPos pos) {
return this.defaults.getRandomValue(random).orElseThrow(IllegalStateException::new);
}

private BlockState calculateOther(RandomSource random, WorldGenLevel level, BlockPos pos) {
int length = this.entries.size();
int index = random.nextInt(length);
return this.entries.get(index).calculate(random, level, pos);
}

public record Entry(ExtendableStateList list, Map<ResourceKey<Biome>, SimpleWeightedRandomList<BlockState>> byBiome, SimpleWeightedRandomList<BlockState> fallback) {

private static boolean canCreate = false;

@Deprecated
public Entry {
if (!canCreate) throw new IllegalStateException("Use ExtendableStateList$Entry#create please!");
}

public static Entry create(ExtendableStateList list, Map<ResourceKey<Biome>, SimpleWeightedRandomList<BlockState>> byBiome, SimpleWeightedRandomList<BlockState> fallback) {
canCreate = true;
Entry e = new Entry(list, byBiome, fallback);
list.entries.add(e);
canCreate = false;
return e;
}

public static Codec<Entry> CODEC = RecordCodecBuilder.create(builder -> builder.group(
StateLists.STATE_LIST_REGISTRY.byNameCodec().fieldOf("parent_state_list").forGetter(Entry::list),
Codec.unboundedMap(ResourceKey.codec(Registries.BIOME), SimpleWeightedRandomList.wrappedCodec(BlockState.CODEC)).fieldOf("by_biome").forGetter(Entry::byBiome),
SimpleWeightedRandomList.wrappedCodec(BlockState.CODEC).fieldOf("fallback").forGetter(Entry::fallback)
).apply(builder, Entry::create));


public BlockState calculate(RandomSource random, WorldGenLevel level, BlockPos pos) {
Holder<Biome> biome = level.getBiome(pos);
Optional<ResourceKey<Biome>> optional = biome.unwrapKey();
if (optional.isPresent()) {
ResourceKey<Biome> key = optional.get();
if (this.byBiome.containsKey(key)) {
return this.byBiome.get(key).getRandomValue(random).orElseThrow(IllegalStateException::new);
}
}
return fallback.getRandomValue(random).orElseThrow(IllegalStateException::new);
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package net.zepalesque.zenith.api.world.feature.gen;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.DoublePlantBlock;
import net.minecraft.world.level.block.state.BlockState;
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.zepalesque.zenith.api.extendablestate.ExtendableStateList;
import net.zepalesque.zenith.core.registry.StateLists;

import java.util.Optional;

public class ExtendableStateListBlockFeature extends Feature<ExtendableStateListBlockFeature.Config> {

public ExtendableStateListBlockFeature(Codec<Config> codec) {
super(codec);
}

public boolean place(FeaturePlaceContext<ExtendableStateListBlockFeature.Config> context) {
ExtendableStateListBlockFeature.Config config = context.config();
WorldGenLevel level = context.level();
BlockPos pos = context.origin();
Optional<BlockPredicate> predicate = context.config().predicate();
BlockState state = config.list().calculate(context.random(), context.level(), pos);
if ((predicate.isEmpty() || predicate.get().test(level, pos)) && state.canSurvive(level, pos)) {
if (state.getBlock() instanceof DoublePlantBlock) {
if (!level.isEmptyBlock(pos.above())) {
return false;
}

DoublePlantBlock.placeAt(level, state, pos, 2);
} else {
level.setBlock(pos, state, 2);
}

return true;
} else {
return false;
}
}


public record Config(ExtendableStateList list, Optional<BlockPredicate> predicate) implements FeatureConfiguration {
public static final Codec<Config> CODEC = RecordCodecBuilder.create((config) -> config.group(
StateLists.STATE_LIST_REGISTRY.byNameCodec().fieldOf("to_place").forGetter(Config::list),
BlockPredicate.CODEC.optionalFieldOf("predicate").forGetter(Config::predicate)
).apply(config, Config::new));
}
}
12 changes: 11 additions & 1 deletion src/main/java/net/zepalesque/zenith/core/Zenith.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import net.neoforged.neoforge.registries.DeferredRegister;
import net.neoforged.neoforge.registries.NewRegistryEvent;
import net.neoforged.neoforge.registries.datamaps.RegisterDataMapTypesEvent;
import net.zepalesque.zenith.api.extendablestate.ExtendableStateList;
import net.zepalesque.zenith.core.registry.StateLists;
import net.zepalesque.zenith.core.registry.ZenithAdvancementTriggers;
import net.zepalesque.zenith.api.biometint.BiomeTint;
import net.zepalesque.zenith.core.registry.BiomeTints;
Expand Down Expand Up @@ -60,7 +62,7 @@ public Zenith(ModContainer mod, IEventBus bus, Dist dist) {
bus.addListener(this::registerDataMaps);
bus.addListener(this::registerRegistries);
bus.addListener(this::dataSetup);
bus.addListener(DataPackRegistryEvent.NewRegistry.class, event -> event.dataPackRegistry(Keys.CONDITION, Condition.ELEMENT_CODEC, Condition.ELEMENT_CODEC));
bus.addListener(this::datapackRegistries);

DeferredRegister<?>[] registers = {
ConditionElements.ELEMENTS,
Expand Down Expand Up @@ -96,6 +98,11 @@ public void registerPackets(RegisterPayloadHandlersEvent event) {
registrar.playToClient(BiomeTintSyncPacket.TYPE, BiomeTintSyncPacket.STREAM_CODEC, BiomeTintSyncPacket::execute);
}

private void datapackRegistries(DataPackRegistryEvent.NewRegistry event) {
event.dataPackRegistry(Keys.CONDITION, Condition.ELEMENT_CODEC, Condition.ELEMENT_CODEC);
event.dataPackRegistry(Keys.EXTENDABLE_STATE_LIST_ENTRY, ExtendableStateList.Entry.CODEC);
}

private void dataSetup(GatherDataEvent event) {
DataGenerator generator = event.getGenerator();
ExistingFileHelper fileHelper = event.getExistingFileHelper();
Expand All @@ -117,6 +124,7 @@ private void registerDataMaps(RegisterDataMapTypesEvent event) {
private void registerRegistries(NewRegistryEvent event) {
event.register(ConditionElements.ELEMENT_REGISTRY);
event.register(BiomeTints.TINT_REGISTRY);
event.register(StateLists.STATE_LIST_REGISTRY);
}

@EventBusSubscriber(modid = MODID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
Expand All @@ -138,6 +146,8 @@ public static class Keys {
public static final ResourceKey<Registry<MapCodec<? extends Condition<?>>>> CONDITION_ELEMENT = ResourceKey.createRegistryKey(Zenith.loc("condition_element"));
public static final ResourceKey<Registry<Condition<?>>> CONDITION = ResourceKey.createRegistryKey(Zenith.loc("condition"));
public static final ResourceKey<Registry<BiomeTint>> BIOME_TINT = ResourceKey.createRegistryKey(Zenith.loc("biome_tint"));
public static final ResourceKey<Registry<ExtendableStateList>> EXTENDABLE_STATE_LIST = ResourceKey.createRegistryKey(Zenith.loc("extendable_state_list"));
public static final ResourceKey<Registry<ExtendableStateList.Entry>> EXTENDABLE_STATE_LIST_ENTRY = ResourceKey.createRegistryKey(Zenith.loc("state_list_entry"));
}


Expand Down
11 changes: 11 additions & 0 deletions src/main/java/net/zepalesque/zenith/core/registry/StateLists.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package net.zepalesque.zenith.core.registry;

import net.minecraft.core.Registry;
import net.neoforged.neoforge.registries.RegistryBuilder;
import net.zepalesque.zenith.api.extendablestate.ExtendableStateList;
import net.zepalesque.zenith.core.Zenith;

public class StateLists {
// public static final DeferredRegister<ExtendableStateList> STATE_LISTS = DeferredRegister.create(Zenith.Keys.EXTENDABLE_STATE_LIST, Zenith.MODID);
public static final Registry<ExtendableStateList> STATE_LIST_REGISTRY = new RegistryBuilder<>(Zenith.Keys.EXTENDABLE_STATE_LIST).sync(true).create();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import net.minecraft.world.level.levelgen.feature.Feature;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
import net.zepalesque.zenith.api.world.feature.gen.ExtendableStateListBlockFeature;
import net.zepalesque.zenith.core.Zenith;
import net.zepalesque.zenith.api.world.feature.gen.BlockWithPredicateFeature;
import net.zepalesque.zenith.api.world.feature.gen.LargeRockFeature;
Expand All @@ -15,4 +16,5 @@ public class ZenithFeatures {
public static DeferredHolder<Feature<?>, Feature<BlockWithPredicateFeature.Config>> BLOCK_WITH_PREDICATE = FEATURES.register("block_with_predicate", () -> new BlockWithPredicateFeature(BlockWithPredicateFeature.Config.CODEC));
public static DeferredHolder<Feature<?>, Feature<SurfaceRuleLakeFeature.Config>> SURFACE_RULE_LAKE = FEATURES.register("surface_rule_lake", () -> new SurfaceRuleLakeFeature(SurfaceRuleLakeFeature.Config.CODEC));
public static DeferredHolder<Feature<?>, Feature<LargeRockFeature.Config>> LARGE_ROCK = FEATURES.register("large_rock", () -> new LargeRockFeature(LargeRockFeature.Config.CODEC));
public static DeferredHolder<Feature<?>, Feature<ExtendableStateListBlockFeature.Config>> EXTENDABLE_STATE_LIST_BLOCK = FEATURES.register("extendable_state_list", () -> new ExtendableStateListBlockFeature(ExtendableStateListBlockFeature.Config.CODEC));
}

0 comments on commit df79ead

Please sign in to comment.