From be0ac598d79debb6dacf6678a644750c6ea08351 Mon Sep 17 00:00:00 2001 From: IkeVoodoo Date: Wed, 13 May 2026 14:38:34 +0200 Subject: [PATCH 1/2] Fixed crash on 1.21.1 when a placed feature is null. --- .../RunFeatureCancellersBiomeModifier.java | 27 ++++-- .../RunFeatureCancellersBiomeModifier.java | 90 +++++++++++++++++++ 2 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/ferreusveritas/dynamictrees/worldgen/biomemodifiers/RunFeatureCancellersBiomeModifier.java diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/RunFeatureCancellersBiomeModifier.java b/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/RunFeatureCancellersBiomeModifier.java index bc9d62518..5498a936e 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/RunFeatureCancellersBiomeModifier.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/RunFeatureCancellersBiomeModifier.java @@ -46,15 +46,30 @@ public void modify(Holder biome, Phase phase, ModifiableBiomeInfo.BiomeIn PlacedFeature placedFeature = placedFeatureHolder.value(); - return placedFeature.getFeatures().anyMatch(configuredFeature -> { - for (FeatureCanceller featureCanceller : featureCancellations.getCancellers()) { - if (featureCanceller.shouldCancel(configuredFeature, featureCancellations)) { - return true; - } + try { + var features = placedFeature.getFeatures(); + if (features == null) { + return false; } + return features.filter(cf -> cf.config() != null).anyMatch(configuredFeature -> { + for (FeatureCanceller featureCanceller : featureCancellations.getCancellers()) { + try { + if (featureCanceller.shouldCancel(configuredFeature, featureCancellations)) { + return true; + } + } catch (NullPointerException e) { + // This should be logged + // In this case, we do not want a single FeatureCanceller to break the entire process. + return false; + } + } + return false; + }); + } catch (NullPointerException e) { + // I don't know how to log this return false; - }); + } })); } } diff --git a/src/main/java/com/ferreusveritas/dynamictrees/worldgen/biomemodifiers/RunFeatureCancellersBiomeModifier.java b/src/main/java/com/ferreusveritas/dynamictrees/worldgen/biomemodifiers/RunFeatureCancellersBiomeModifier.java new file mode 100644 index 000000000..f523d3e09 --- /dev/null +++ b/src/main/java/com/ferreusveritas/dynamictrees/worldgen/biomemodifiers/RunFeatureCancellersBiomeModifier.java @@ -0,0 +1,90 @@ +package com.ferreusveritas.dynamictrees.worldgen.biomemodifiers; + +import com.ferreusveritas.dynamictrees.DynamicTrees; +import com.ferreusveritas.dynamictrees.api.worldgen.BiomePropertySelectors; +import com.ferreusveritas.dynamictrees.api.worldgen.FeatureCanceller; +import com.ferreusveritas.dynamictrees.init.DTConfigs; +import com.ferreusveritas.dynamictrees.init.DTRegistries; +import com.ferreusveritas.dynamictrees.worldgen.BiomeDatabase; +import com.ferreusveritas.dynamictrees.worldgen.FeatureCancellationRegistry; +import com.mojang.serialization.Codec; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import net.minecraftforge.common.world.BiomeGenerationSettingsBuilder; +import net.minecraftforge.common.world.BiomeModifier; +import net.minecraftforge.common.world.ModifiableBiomeInfo; + +public class RunFeatureCancellersBiomeModifier implements BiomeModifier { + public static final TagKey FEATURE_CANCELLER_EXCLUSIONS_KEY = TagKey.create(Registries.PLACED_FEATURE, + new ResourceLocation(DynamicTrees.MOD_ID, "feature_canceller_exclusions")); + + @Override + public void modify(Holder biome, Phase phase, ModifiableBiomeInfo.BiomeInfo.Builder builder) { + if (phase == Phase.REMOVE && DTConfigs.WORLD_GEN.get()) { + ResourceKey biomeKey = biome.unwrapKey().orElseThrow(); + BiomeGenerationSettingsBuilder generationSettings = builder.getGenerationSettings(); + + BiomePropertySelectors.NormalFeatureCancellation featureCancellations = new BiomePropertySelectors.NormalFeatureCancellation(); + + for (FeatureCancellationRegistry.Entry entry : FeatureCancellationRegistry.getCancellations()) { + if (entry.biomes().containsKey(biomeKey)) { + if (entry.operation() == BiomeDatabase.Operation.REPLACE) + featureCancellations.reset(); + featureCancellations.addFrom(entry.cancellations()); + } + } + + // final ResourceLocation biomeName = biome.unwrapKey().map(ResourceKey::location).orElse(null); + // + // if (biomeName == null) { + // return; + // } + // + + featureCancellations.getDecorationSteps().forEach(stage -> generationSettings.getFeatures(stage).removeIf(placedFeatureHolder -> { + // If you want a placed feature to be entirely excluded from cancellation by any feature cancellers, + // add it to the dynamictrees:tags/worldgen/placed_feature/feature_canceller_exclusions tag. + if (placedFeatureHolder.is(FEATURE_CANCELLER_EXCLUSIONS_KEY)) + return false; + + PlacedFeature placedFeature = placedFeatureHolder.value(); + + try { + var features = placedFeature.getFeatures(); + if (features == null) { + return false; + } + + return features.filter(cf -> cf.config() != null).anyMatch(configuredFeature -> { + for (FeatureCanceller featureCanceller : featureCancellations.getCancellers()) { + try { + if (featureCanceller.shouldCancel(configuredFeature, featureCancellations)) { + return true; + } + } catch (NullPointerException e) { + // This should be logged + // In this case, we do not want a single FeatureCanceller to break the entire process. + return false; + } + } + return false; + }); + } catch (NullPointerException e) { + // I don't know how to log this + return false; + } + })); + } + } + + @Override + public Codec codec() { + return DTRegistries.RUN_FEATURE_CANCELLERS_BIOME_MODIFIER.get(); + } +} \ No newline at end of file From 9de7aac6df3f86f8a42a5815e00ee76c7bc48753 Mon Sep 17 00:00:00 2001 From: IkeVoodoo Date: Wed, 13 May 2026 14:47:01 +0200 Subject: [PATCH 2/2] Delete accidentally created file. --- .../RunFeatureCancellersBiomeModifier.java | 90 ------------------- 1 file changed, 90 deletions(-) delete mode 100644 src/main/java/com/ferreusveritas/dynamictrees/worldgen/biomemodifiers/RunFeatureCancellersBiomeModifier.java diff --git a/src/main/java/com/ferreusveritas/dynamictrees/worldgen/biomemodifiers/RunFeatureCancellersBiomeModifier.java b/src/main/java/com/ferreusveritas/dynamictrees/worldgen/biomemodifiers/RunFeatureCancellersBiomeModifier.java deleted file mode 100644 index f523d3e09..000000000 --- a/src/main/java/com/ferreusveritas/dynamictrees/worldgen/biomemodifiers/RunFeatureCancellersBiomeModifier.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.ferreusveritas.dynamictrees.worldgen.biomemodifiers; - -import com.ferreusveritas.dynamictrees.DynamicTrees; -import com.ferreusveritas.dynamictrees.api.worldgen.BiomePropertySelectors; -import com.ferreusveritas.dynamictrees.api.worldgen.FeatureCanceller; -import com.ferreusveritas.dynamictrees.init.DTConfigs; -import com.ferreusveritas.dynamictrees.init.DTRegistries; -import com.ferreusveritas.dynamictrees.worldgen.BiomeDatabase; -import com.ferreusveritas.dynamictrees.worldgen.FeatureCancellationRegistry; -import com.mojang.serialization.Codec; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.TagKey; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.levelgen.placement.PlacedFeature; -import net.minecraftforge.common.world.BiomeGenerationSettingsBuilder; -import net.minecraftforge.common.world.BiomeModifier; -import net.minecraftforge.common.world.ModifiableBiomeInfo; - -public class RunFeatureCancellersBiomeModifier implements BiomeModifier { - public static final TagKey FEATURE_CANCELLER_EXCLUSIONS_KEY = TagKey.create(Registries.PLACED_FEATURE, - new ResourceLocation(DynamicTrees.MOD_ID, "feature_canceller_exclusions")); - - @Override - public void modify(Holder biome, Phase phase, ModifiableBiomeInfo.BiomeInfo.Builder builder) { - if (phase == Phase.REMOVE && DTConfigs.WORLD_GEN.get()) { - ResourceKey biomeKey = biome.unwrapKey().orElseThrow(); - BiomeGenerationSettingsBuilder generationSettings = builder.getGenerationSettings(); - - BiomePropertySelectors.NormalFeatureCancellation featureCancellations = new BiomePropertySelectors.NormalFeatureCancellation(); - - for (FeatureCancellationRegistry.Entry entry : FeatureCancellationRegistry.getCancellations()) { - if (entry.biomes().containsKey(biomeKey)) { - if (entry.operation() == BiomeDatabase.Operation.REPLACE) - featureCancellations.reset(); - featureCancellations.addFrom(entry.cancellations()); - } - } - - // final ResourceLocation biomeName = biome.unwrapKey().map(ResourceKey::location).orElse(null); - // - // if (biomeName == null) { - // return; - // } - // - - featureCancellations.getDecorationSteps().forEach(stage -> generationSettings.getFeatures(stage).removeIf(placedFeatureHolder -> { - // If you want a placed feature to be entirely excluded from cancellation by any feature cancellers, - // add it to the dynamictrees:tags/worldgen/placed_feature/feature_canceller_exclusions tag. - if (placedFeatureHolder.is(FEATURE_CANCELLER_EXCLUSIONS_KEY)) - return false; - - PlacedFeature placedFeature = placedFeatureHolder.value(); - - try { - var features = placedFeature.getFeatures(); - if (features == null) { - return false; - } - - return features.filter(cf -> cf.config() != null).anyMatch(configuredFeature -> { - for (FeatureCanceller featureCanceller : featureCancellations.getCancellers()) { - try { - if (featureCanceller.shouldCancel(configuredFeature, featureCancellations)) { - return true; - } - } catch (NullPointerException e) { - // This should be logged - // In this case, we do not want a single FeatureCanceller to break the entire process. - return false; - } - } - return false; - }); - } catch (NullPointerException e) { - // I don't know how to log this - return false; - } - })); - } - } - - @Override - public Codec codec() { - return DTRegistries.RUN_FEATURE_CANCELLERS_BIOME_MODIFIER.get(); - } -} \ No newline at end of file