mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-25 21:40:05 +00:00
Bounded sea surface decoration
- Sea surface decorators respect engine and output ceilings in every placement mode - Clipped sea stacks retain their top palette - Tests cover short outputs negative bases and engine ceilings - Multi-palette tests verify shared random sources match fresh per-block sources
This commit is contained in:
1 parent
b9b969f1f9
commit
75353d43c7
3 files changed
+115
-22
No files matched your search
@@ -39,6 +39,10 @@ public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
|
|||||||
@Override
|
@Override
|
||||||
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1,
|
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1,
|
||||||
Hunk<PlatformBlockState> data, IrisBiome biome, int height, int max) {
|
Hunk<PlatformBlockState> data, IrisBiome biome, int height, int max) {
|
||||||
|
int maxBaseY = Math.min(max, Math.min(getEngine().getHeight(), data.getHeight()) - 1);
|
||||||
|
if (height < 0 || height >= maxBaseY) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
RNG rng = getRNG(realX, realZ);
|
RNG rng = getRNG(realX, realZ);
|
||||||
IrisDecorator decorator = DecoratorCore.pickDecorator(biome, getPart(), partRNG, rng, getData(), realX, realZ);
|
IrisDecorator decorator = DecoratorCore.pickDecorator(biome, getPart(), partRNG, rng, getData(), realX, realZ);
|
||||||
|
|
||||||
@@ -48,8 +52,7 @@ public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
|
|||||||
|
|
||||||
if (!decorator.isStacking()) {
|
if (!decorator.isStacking()) {
|
||||||
int targetY = height + 1;
|
int targetY = height + 1;
|
||||||
if (height >= 0 && targetY < getEngine().getHeight()
|
if (DecoratorCore.canReplaceStackTarget(data.get(x, targetY, z), false)) {
|
||||||
&& DecoratorCore.canReplaceStackTarget(data.get(x, targetY, z), false)) {
|
|
||||||
PlatformBlockState block = decorator.getBlockData100(biome, rng, realX, height, realZ, getData());
|
PlatformBlockState block = decorator.getBlockData100(biome, rng, realX, height, realZ, getData());
|
||||||
if (block != null) {
|
if (block != null) {
|
||||||
data.set(x, targetY, z, block);
|
data.set(x, targetY, z, block);
|
||||||
@@ -58,30 +61,15 @@ public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stack = DecoratorCore.computeStack(decorator, rng, realX, realZ, getData(), max - height);
|
int stack = Math.min(maxBaseY - height,
|
||||||
|
DecoratorCore.computeStack(decorator, rng, realX, realZ, getData(), max - height));
|
||||||
if (stack == 1) {
|
|
||||||
int targetY = height + 1;
|
|
||||||
if (targetY >= data.getHeight() || !DecoratorCore.canReplaceStackTarget(data.get(x, targetY, z), false)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlatformBlockState block = decorator.getBlockDataForTop(biome, rng, realX, height, realZ, getData());
|
|
||||||
if (block != null) {
|
|
||||||
data.set(x, targetY, z, block);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int engineHeight = getEngine().getHeight();
|
|
||||||
for (int i = 0; i < stack; i++) {
|
for (int i = 0; i < stack; i++) {
|
||||||
int h = height + i;
|
int h = height + i;
|
||||||
int targetY = h + 1;
|
int targetY = h + 1;
|
||||||
if (h >= max || targetY >= engineHeight
|
if (!DecoratorCore.canReplaceStackTarget(data.get(x, targetY, z), false)) {
|
||||||
|| !DecoratorCore.canReplaceStackTarget(data.get(x, targetY, z), false)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
double threshold = ((double) i) / (stack - 1);
|
double threshold = stack == 1 ? 1.0 : ((double) i) / (stack - 1);
|
||||||
PlatformBlockState block = threshold >= decorator.getTopThreshold()
|
PlatformBlockState block = threshold >= decorator.getTopThreshold()
|
||||||
? decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData())
|
? decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData())
|
||||||
: decorator.getBlockData100(biome, rng, realX, h, realZ, getData());
|
: decorator.getBlockData100(biome, rng, realX, h, realZ, getData());
|
||||||
|
|||||||
+36
-1
@@ -77,16 +77,51 @@ public class IrisSeaDecoratorBoundsTest {
|
|||||||
assertNull(fixture.output.get(0, 4, 0));
|
assertNull(fixture.output.get(0, 4, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void surfaceStackUsesTheShorterOutputHeight() {
|
||||||
|
Fixture fixture = new Fixture(8, true);
|
||||||
|
when(fixture.engine.getHeight()).thenReturn(64);
|
||||||
|
fixture.stacking(200, 30);
|
||||||
|
|
||||||
|
fixture.decorate(6, 64);
|
||||||
|
|
||||||
|
assertSame(fixture.top, fixture.output.get(0, 7, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void surfaceSingleRejectsOutputCeiling() {
|
||||||
|
Fixture fixture = new Fixture(8, true);
|
||||||
|
when(fixture.engine.getHeight()).thenReturn(64);
|
||||||
|
|
||||||
|
fixture.decorate(7, 64);
|
||||||
|
|
||||||
|
assertNull(fixture.output.get(0, 7, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void surfaceSingleStackRejectsNegativeBaseAndEngineCeiling() {
|
||||||
|
Fixture fixture = new Fixture(16, true);
|
||||||
|
when(fixture.engine.getHeight()).thenReturn(8);
|
||||||
|
fixture.stacking(1, 30);
|
||||||
|
when(fixture.decorator.isScaleStack()).thenReturn(false);
|
||||||
|
|
||||||
|
fixture.decorate(-1, 16);
|
||||||
|
fixture.decorate(7, 16);
|
||||||
|
|
||||||
|
assertNull(fixture.output.get(0, 0, 0));
|
||||||
|
assertNull(fixture.output.get(0, 8, 0));
|
||||||
|
}
|
||||||
|
|
||||||
private static final class Fixture {
|
private static final class Fixture {
|
||||||
private final IrisDecorator decorator = mock(IrisDecorator.class);
|
private final IrisDecorator decorator = mock(IrisDecorator.class);
|
||||||
private final IrisBiome biome = mock(IrisBiome.class);
|
private final IrisBiome biome = mock(IrisBiome.class);
|
||||||
private final PlatformBlockState body = mock(PlatformBlockState.class);
|
private final PlatformBlockState body = mock(PlatformBlockState.class);
|
||||||
private final PlatformBlockState top = mock(PlatformBlockState.class);
|
private final PlatformBlockState top = mock(PlatformBlockState.class);
|
||||||
|
private final Engine engine = mock(Engine.class, RETURNS_DEEP_STUBS);
|
||||||
private final Hunk<PlatformBlockState> output;
|
private final Hunk<PlatformBlockState> output;
|
||||||
private final IrisEngineDecorator placement;
|
private final IrisEngineDecorator placement;
|
||||||
|
|
||||||
private Fixture(int height, boolean surface) {
|
private Fixture(int height, boolean surface) {
|
||||||
Engine engine = mock(Engine.class, RETURNS_DEEP_STUBS);
|
|
||||||
when(engine.getHeight()).thenReturn(height);
|
when(engine.getHeight()).thenReturn(height);
|
||||||
output = Hunk.newArrayHunk(1, height, 1);
|
output = Hunk.newArrayHunk(1, height, 1);
|
||||||
IrisDecorationPart part = surface ? IrisDecorationPart.SEA_SURFACE : IrisDecorationPart.SEA_FLOOR;
|
IrisDecorationPart part = surface ? IrisDecorationPart.SEA_SURFACE : IrisDecorationPart.SEA_FLOOR;
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package art.arcane.iris.engine.object.tree;
|
||||||
|
|
||||||
|
import art.arcane.iris.engine.object.IrisBlockData;
|
||||||
|
import art.arcane.iris.engine.object.IrisMaterialPalette;
|
||||||
|
import art.arcane.iris.engine.object.IrisProceduralTree;
|
||||||
|
import art.arcane.iris.spi.PlatformBlockState;
|
||||||
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
|
import art.arcane.volmlib.util.math.RNG;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
public class TreeBlockResolverTest {
|
||||||
|
@Test
|
||||||
|
public void sharedPaletteRandomSourceMatchesFreshPerVoxelSources() {
|
||||||
|
IrisProceduralTree tree = new IrisProceduralTree();
|
||||||
|
tree.setSeed(84261L);
|
||||||
|
tree.setTrunkPalette(palette("oak_log", "spruce_log"));
|
||||||
|
tree.setLeavesPalette(palette("oak_leaves", "birch_leaves"));
|
||||||
|
tree.setSecondaryTrunkPalette(palette("birch_log", "jungle_log"));
|
||||||
|
tree.setSecondaryLeavesPalette(palette("spruce_leaves", "jungle_leaves"));
|
||||||
|
RNG shared = new RNG(tree.getSeed());
|
||||||
|
List<String> freshBlocks = new ArrayList<>();
|
||||||
|
List<String> sharedBlocks = new ArrayList<>();
|
||||||
|
Set<String> materials = new HashSet<>();
|
||||||
|
TreeBlockCanvas.Role[] roles = {
|
||||||
|
TreeBlockCanvas.Role.TRUNK, TreeBlockCanvas.Role.LEAF,
|
||||||
|
TreeBlockCanvas.Role.SECONDARY_TRUNK, TreeBlockCanvas.Role.SECONDARY_LEAF
|
||||||
|
};
|
||||||
|
for (int x = -8; x <= 8; x++) {
|
||||||
|
for (int y = 0; y < 24; y++) {
|
||||||
|
TreeBlockCanvas.Vec position = new TreeBlockCanvas.Vec(x, y, x - y);
|
||||||
|
TreeBlockCanvas.Cell cell = new TreeBlockCanvas.Cell(
|
||||||
|
roles[Math.floorMod(x + y, roles.length)], TreeBlockCanvas.Axis.NONE, false, -1, null);
|
||||||
|
PlatformBlockState expected = TreeBlockResolver.resolve(tree, null, cell, position, new RNG(tree.getSeed()));
|
||||||
|
PlatformBlockState actual = TreeBlockResolver.resolve(tree, null, cell, position, shared);
|
||||||
|
freshBlocks.add(position + ":" + expected.key());
|
||||||
|
sharedBlocks.add(position + ":" + actual.key());
|
||||||
|
materials.add(actual.key());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(freshBlocks, sharedBlocks);
|
||||||
|
assertEquals(new RNG(tree.getSeed()).nextLong(), shared.nextLong());
|
||||||
|
assertTrue(materials.size() > roles.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IrisMaterialPalette palette(String first, String second) {
|
||||||
|
IrisBlockData firstBlock = block(first);
|
||||||
|
IrisBlockData secondBlock = block(second);
|
||||||
|
return new IrisMaterialPalette().setPalette(new KList<>(firstBlock, secondBlock));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IrisBlockData block(String material) {
|
||||||
|
PlatformBlockState state = mock(PlatformBlockState.class);
|
||||||
|
when(state.key()).thenReturn("minecraft:" + material);
|
||||||
|
IrisBlockData block = mock(IrisBlockData.class);
|
||||||
|
when(block.getWeight()).thenReturn(1);
|
||||||
|
when(block.getBlockData(null)).thenReturn(state);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user