Grow speleothems from decorators and keep them supported

Dripstone and sulfur spikes are placed as oriented, thickness-graded
columns by the surface and ceiling decorators through a shared
IrisSpeleothems helper, replacing the ad hoc dripstone fixups, and the
stacking path is unified for both directions. The perfection modifier
renormalizes a spike whose support a pool replaced, dropping the
unsupported run and re-tipping what remains. Surface sturdiness is asked
per face now, so a downward spike tests the ceiling it hangs from.
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-03 05:03:14 -04:00
1 parent fd66b41bad
commit 5053a644c7
9 files changed
+839 -127

No files matched your search

@@ -33,7 +33,7 @@ import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.PointedDripstoneBlock;
import net.minecraft.world.level.block.SpeleothemBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.SpeleothemThickness;
@@ -476,8 +476,8 @@ public final class ModdedBlockResolution {
public static boolean isUpdatable(BlockState state) {
return isStorage(state)
|| (state.getBlock() instanceof PointedDripstoneBlock
&& state.getValue(PointedDripstoneBlock.THICKNESS) == SpeleothemThickness.TIP);
|| (state.getBlock() instanceof SpeleothemBlock
&& state.getValue(SpeleothemBlock.THICKNESS) == SpeleothemThickness.TIP);
}
public static boolean isFoliage(BlockState state) {
@@ -95,8 +95,8 @@ public final class ModdedDecoratorHooks implements DecoratorPlatformHooks.FaceFi
}
@Override
public boolean canGoOn(PlatformBlockState surface) {
return isFaceSturdy((BlockState) surface.nativeHandle(), Direction.UP);
public boolean canGoOn(PlatformBlockState surface, boolean upward) {
return isFaceSturdy((BlockState) surface.nativeHandle(), upward ? Direction.UP : Direction.DOWN);
}
private static boolean isFaceSturdy(BlockState state, Direction face) {
@@ -1,8 +1,16 @@
package art.arcane.iris.modded;
import art.arcane.iris.engine.decorator.DecoratorPlatformHooks;
import art.arcane.iris.engine.decorator.IrisSpeleothems;
import art.arcane.iris.spi.PlatformBlockState;
import art.arcane.iris.util.project.hunk.Hunk;
import net.minecraft.SharedConstants;
import net.minecraft.server.Bootstrap;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SpeleothemBlock;
import net.minecraft.world.level.block.state.properties.SpeleothemThickness;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -60,4 +68,39 @@ public class ModdedBlockResolutionContractTest {
assertFalse(ModdedBlockResolution.canPlaceOnto(Blocks.CACTUS, Blocks.STONE));
assertTrue(ModdedBlockResolution.isDecorant(Blocks.CACTUS.defaultBlockState()));
}
@Test
public void sulfurAndDripstoneTipsReceivePostLoadUpdates() {
for (Block block : new Block[]{Blocks.SULFUR_SPIKE, Blocks.POINTED_DRIPSTONE}) {
for (SpeleothemThickness thickness : SpeleothemThickness.values()) {
assertEquals(thickness == SpeleothemThickness.TIP,
ModdedBlockResolution.isUpdatable(block.defaultBlockState()
.setValue(SpeleothemBlock.THICKNESS, thickness)));
}
}
assertFalse(ModdedBlockResolution.isUpdatable(Blocks.STONE.defaultBlockState()));
}
@Test
public void nativeSpikesUseModdedSupportFaces() {
ModdedDecoratorHooks hooks = new ModdedDecoratorHooks();
DecoratorPlatformHooks.Bindings previous = DecoratorPlatformHooks.bind(hooks, hooks);
try {
for (String material : new String[]{"minecraft:sulfur_spike", "minecraft:pointed_dripstone"}) {
for (boolean upward : new boolean[]{true, false}) {
Hunk<PlatformBlockState> output = Hunk.newArrayHunk(1, 3, 1);
PlatformBlockState spike = ModdedBlockResolution.get(material
+ "[vertical_direction=" + (upward ? "up" : "down") + ",thickness=tip]");
int supportY = upward ? 0 : 2;
output.set(0, 1, 0, spike);
output.set(0, supportY, 0, ModdedBlockResolution.get("minecraft:stone_slab[type=top]"));
assertEquals(upward, IrisSpeleothems.isSupported(spike, output, 0, 0, 1));
output.set(0, supportY, 0, ModdedBlockResolution.get("minecraft:stone_slab[type=bottom]"));
assertEquals(!upward, IrisSpeleothems.isSupported(spike, output, 0, 0, 1));
}
}
} finally {
DecoratorPlatformHooks.restore(previous);
}
}
}