mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-12 03:24:14 +00:00
Reused formation palette sources
- Formation resolution shares one base palette source per object - Strata reuse one seeded source per occupied band - Mixed palette tests preserve block choices across negative bands and reversed traversal
This commit is contained in:
+23
-10
@@ -25,35 +25,48 @@ import art.arcane.iris.engine.object.IrisProceduralBlocks;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.common.math.Vector3i;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public final class FormationBlockResolver {
|
||||
private FormationBlockResolver() {
|
||||
private final IrisFormation formation;
|
||||
private final IrisData data;
|
||||
private final RNG paletteRng;
|
||||
private final Int2ObjectOpenHashMap<RNG> strataRngs = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
public FormationBlockResolver(IrisFormation formation, IrisData data) {
|
||||
this.formation = formation;
|
||||
this.data = data;
|
||||
paletteRng = new RNG(formation.getSeed());
|
||||
}
|
||||
|
||||
public static PlatformBlockState resolve(IrisFormation f, IrisData data, FormationCanvas.Role role, Vector3i raw) {
|
||||
public PlatformBlockState resolve(FormationCanvas.Role role, Vector3i raw) {
|
||||
int x = raw.getBlockX();
|
||||
int y = raw.getBlockY();
|
||||
int z = raw.getBlockZ();
|
||||
RNG paletteRng = new RNG(f.getSeed());
|
||||
|
||||
if (role == FormationCanvas.Role.CAP && capDefined(f)) {
|
||||
PlatformBlockState cap = IrisProceduralBlocks.resolve(f.getCapBlock(), f.getCapPalette(), data, x, y, z, paletteRng);
|
||||
if (role == FormationCanvas.Role.CAP && capDefined(formation)) {
|
||||
PlatformBlockState cap = IrisProceduralBlocks.resolve(formation.getCapBlock(), formation.getCapPalette(), data, x, y, z, paletteRng);
|
||||
if (cap != null) {
|
||||
return cap;
|
||||
}
|
||||
}
|
||||
|
||||
if (strataDefined(f)) {
|
||||
IrisMaterialPalette strata = f.getStrataPalette();
|
||||
int thickness = Math.max(1, f.getStrataThickness());
|
||||
if (strataDefined(formation)) {
|
||||
IrisMaterialPalette strata = formation.getStrataPalette();
|
||||
int thickness = Math.max(1, formation.getStrataThickness());
|
||||
int band = Math.floorDiv(y, thickness);
|
||||
PlatformBlockState strataState = strata.get(new RNG(f.getSeed() + (band * 31L)), x, band, z, data);
|
||||
RNG strataRng = strataRngs.get(band);
|
||||
if (strataRng == null) {
|
||||
strataRng = new RNG(formation.getSeed() + band * 31L);
|
||||
strataRngs.put(band, strataRng);
|
||||
}
|
||||
PlatformBlockState strataState = strata.get(strataRng, x, band, z, data);
|
||||
if (strataState != null) {
|
||||
return strataState;
|
||||
}
|
||||
}
|
||||
|
||||
return IrisProceduralBlocks.resolve(f.getBlock(), f.getBlockPalette(), data, x, y, z, paletteRng);
|
||||
return IrisProceduralBlocks.resolve(formation.getBlock(), formation.getBlockPalette(), data, x, y, z, paletteRng);
|
||||
}
|
||||
|
||||
private static boolean capDefined(IrisFormation f) {
|
||||
|
||||
@@ -62,8 +62,9 @@ public final class FormationGenerator {
|
||||
}
|
||||
|
||||
Map<Vector3i, PlatformBlockState> resolved = new HashMap<>();
|
||||
FormationBlockResolver resolver = new FormationBlockResolver(f, data);
|
||||
for (Map.Entry<Vector3i, FormationCanvas.Role> entry : canvas.getCells().entrySet()) {
|
||||
PlatformBlockState bd = FormationBlockResolver.resolve(f, data, entry.getValue(), entry.getKey());
|
||||
PlatformBlockState bd = resolver.resolve(entry.getValue(), entry.getKey());
|
||||
if (bd == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package art.arcane.iris.engine.object.formation;
|
||||
|
||||
import art.arcane.iris.engine.object.IrisBlockData;
|
||||
import art.arcane.iris.engine.object.IrisFormation;
|
||||
import art.arcane.iris.engine.object.IrisMaterialPalette;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.common.math.Vector3i;
|
||||
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.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class FormationBlockResolverTest {
|
||||
@Test
|
||||
public void sharedResolverMatchesFreshPaletteSeedsAcrossBands() {
|
||||
IrisFormation formation = new IrisFormation().setSeed(43191L).setStrataThickness(3);
|
||||
IrisMaterialPalette body = palette("stone", "andesite");
|
||||
IrisMaterialPalette cap = palette("granite", "diorite");
|
||||
IrisMaterialPalette strata = palette("terracotta", "red_terracotta");
|
||||
formation.setBlockPalette(body);
|
||||
List<Vector3i> positions = new ArrayList<>();
|
||||
for (int x = -8; x <= 8; x++) {
|
||||
for (int y = -12; y <= 24; y++) {
|
||||
positions.add(new Vector3i(x, y, x - y));
|
||||
}
|
||||
}
|
||||
Set<String> materials = new HashSet<>();
|
||||
for (boolean withStrata : new boolean[]{false, true}) {
|
||||
formation.setStrataPalette(withStrata ? strata : null);
|
||||
for (boolean withCap : new boolean[]{false, true}) {
|
||||
formation.setCapPalette(withCap ? cap : null);
|
||||
FormationBlockResolver resolver = new FormationBlockResolver(formation, null);
|
||||
for (int pass = 0; pass < 2; pass++) {
|
||||
for (Vector3i position : positions) {
|
||||
FormationCanvas.Role role = position.getBlockX() % 2 == 0
|
||||
? FormationCanvas.Role.CAP : FormationCanvas.Role.BODY;
|
||||
IrisMaterialPalette expectedPalette = withCap && role == FormationCanvas.Role.CAP
|
||||
? cap : withStrata ? strata : body;
|
||||
int sampleY = expectedPalette == strata
|
||||
? Math.floorDiv(position.getBlockY(), formation.getStrataThickness()) : position.getBlockY();
|
||||
long sampleSeed = formation.getSeed() + (expectedPalette == strata ? sampleY * 31L : 0L);
|
||||
RNG fresh = new RNG(sampleSeed);
|
||||
PlatformBlockState expected = expectedPalette.get(fresh,
|
||||
position.getBlockX(), sampleY, position.getBlockZ(), null);
|
||||
assertSame(expected, resolver.resolve(role, position));
|
||||
assertEquals(new RNG(sampleSeed).nextLong(), fresh.nextLong());
|
||||
materials.add(expected.key());
|
||||
}
|
||||
Collections.reverse(positions);
|
||||
}
|
||||
}
|
||||
}
|
||||
assertTrue(materials.size() == 6);
|
||||
}
|
||||
|
||||
private static IrisMaterialPalette palette(String first, String second) {
|
||||
return new IrisMaterialPalette().setPalette(new KList<>(block(first), block(second)));
|
||||
}
|
||||
|
||||
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