mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-07-24 07:40:56 +00:00
f
This commit is contained in:
+1
-1
@@ -37,7 +37,7 @@ plugins {
|
||||
|
||||
def lib = 'art.arcane.iris.util'
|
||||
String volmLibCoordinate = providers.gradleProperty('volmLibCoordinate')
|
||||
.orElse('com.github.VolmitSoftware:VolmLib:4c38988b344792a79f925f57f8a675bc85fc1bed')
|
||||
.orElse('com.github.VolmitSoftware:VolmLib:d9026a7c8ebc391c8109f401ce79a0ce65df3969')
|
||||
.get()
|
||||
String sentryAuthToken = findProperty('sentry.auth.token') as String ?: System.getenv('SENTRY_AUTH_TOKEN')
|
||||
boolean hasSentryAuthToken = sentryAuthToken != null && !sentryAuthToken.isBlank()
|
||||
|
||||
@@ -163,7 +163,6 @@ final class DecoratorCore {
|
||||
}
|
||||
data.set(x, height, z, fixFacesForHunk(
|
||||
decorator.getForceBlock().getBlockData(irisData), data, x, z, realX, height, realZ, mantle));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!decorator.isForcePlace()) {
|
||||
|
||||
+17
-9
@@ -135,36 +135,42 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
||||
|
||||
ObjectPlaceMode mode = structure.getPlaceMode();
|
||||
int failedPieces = 0;
|
||||
Long2IntOpenHashMap foundationColumns = placement.getStilt() == null
|
||||
IrisStructureStiltSettings stilt = placement.getStilt();
|
||||
Long2IntOpenHashMap foundationColumns = stilt == null
|
||||
? null : new Long2IntOpenHashMap();
|
||||
boolean supportNonOccluding = stilt != null && stilt.isSupportNonOccluding();
|
||||
if (placement.isUnderground()) {
|
||||
ObjectPlaceMode undergroundMode = (mode == ObjectPlaceMode.ORGANIC_STILT || mode == ObjectPlaceMode.CEILING_HANG)
|
||||
? mode : ObjectPlaceMode.STRUCTURE_PIECE;
|
||||
for (PlacedStructurePiece p : pieces) {
|
||||
if (placeObject(writer, structure, p, undergroundMode, p.getY(), rng, foundationColumns) == -1) {
|
||||
if (placeObject(writer, structure, p, undergroundMode, p.getY(), rng,
|
||||
foundationColumns, supportNonOccluding) == -1) {
|
||||
failedPieces++;
|
||||
}
|
||||
}
|
||||
} else if (mode == ObjectPlaceMode.STRUCTURE_PIECE || mode == ObjectPlaceMode.FLOATING) {
|
||||
for (PlacedStructurePiece p : pieces) {
|
||||
if (placeObject(writer, structure, p, ObjectPlaceMode.STRUCTURE_PIECE, p.getY(), rng, foundationColumns) == -1) {
|
||||
if (placeObject(writer, structure, p, ObjectPlaceMode.STRUCTURE_PIECE, p.getY(), rng,
|
||||
foundationColumns, supportNonOccluding) == -1) {
|
||||
failedPieces++;
|
||||
}
|
||||
}
|
||||
} else if (pieces.size() == 1) {
|
||||
if (placeObject(writer, structure, pieces.getFirst(), mode, -1, rng, foundationColumns) == -1) {
|
||||
if (placeObject(writer, structure, pieces.getFirst(), mode, -1, rng,
|
||||
foundationColumns, supportNonOccluding) == -1) {
|
||||
failedPieces++;
|
||||
}
|
||||
} else {
|
||||
for (PlacedStructurePiece p : pieces) {
|
||||
if (placeObject(writer, structure, p, ObjectPlaceMode.STRUCTURE_PIECE, p.getY(), rng, foundationColumns) == -1) {
|
||||
if (placeObject(writer, structure, p, ObjectPlaceMode.STRUCTURE_PIECE, p.getY(), rng,
|
||||
foundationColumns, supportNonOccluding) == -1) {
|
||||
failedPieces++;
|
||||
}
|
||||
}
|
||||
}
|
||||
requireAppliedPieces(resolved, cx, cz, failedPieces);
|
||||
if (failedPieces == 0 && placement.getStilt() != null) {
|
||||
placeFoundation(writer, foundationColumns, placement.getStilt(), rng, !placement.isUnderground());
|
||||
if (failedPieces == 0 && stilt != null) {
|
||||
placeFoundation(writer, foundationColumns, stilt, rng, !placement.isUnderground());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,7 +539,8 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
||||
}
|
||||
|
||||
private int placeObject(MantleWriter writer, IrisStructure structure, PlacedStructurePiece p,
|
||||
ObjectPlaceMode mode, int y, RNG rng, Long2IntOpenHashMap foundationColumns) {
|
||||
ObjectPlaceMode mode, int y, RNG rng, Long2IntOpenHashMap foundationColumns,
|
||||
boolean supportNonOccluding) {
|
||||
IrisObject object = p.getObject();
|
||||
String objectKey = object.getLoadKey();
|
||||
IrisObjectPlacement config = structure.createLootPlacement(objectKey);
|
||||
@@ -549,7 +556,8 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
||||
String marker = structurePlacementMarker(structure, p, objectKey);
|
||||
return object.place(p.getX(), placeY, p.getZ(), writer, config, rng, (position, state) -> {
|
||||
StructureFoundationPlanner.recordBaseCell(
|
||||
foundationColumns, position.getX(), position.getY(), position.getZ(), state);
|
||||
foundationColumns, position.getX(), position.getY(), position.getZ(), state,
|
||||
supportNonOccluding);
|
||||
if (marker != null && shouldWriteStructureMarker(state)) {
|
||||
writer.setData(position.getX(), position.getY(), position.getZ(), marker);
|
||||
}
|
||||
|
||||
+3
-2
@@ -13,8 +13,9 @@ final class StructureFoundationPlanner {
|
||||
}
|
||||
|
||||
static void recordBaseCell(Long2IntOpenHashMap columns, int x, int y, int z,
|
||||
PlatformBlockState state) {
|
||||
if (columns == null || state == null || !state.isOccluding()) {
|
||||
PlatformBlockState state, boolean supportNonOccluding) {
|
||||
if (columns == null || state == null
|
||||
|| !(supportNonOccluding ? state.isSolid() : state.isOccluding())) {
|
||||
return;
|
||||
}
|
||||
long columnKey = pack(x, z);
|
||||
|
||||
@@ -24,6 +24,7 @@ import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisDepositGenerator;
|
||||
import art.arcane.iris.engine.object.IrisDepositVariant;
|
||||
import art.arcane.iris.engine.object.IrisDimension;
|
||||
import art.arcane.iris.engine.object.IrisDimensionCarvingResolver;
|
||||
import art.arcane.iris.engine.object.IrisObject;
|
||||
import art.arcane.iris.engine.object.IrisProceduralBlocks;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
@@ -87,6 +88,7 @@ public class IrisDepositModifier extends EngineAssignedModifier<PlatformBlockSta
|
||||
}
|
||||
|
||||
public void generate(IrisDepositGenerator k, MantleChunk chunk, Hunk<PlatformBlockState> data, RNG rng, int cx, int cz, boolean safe, HeightMap he, ChunkContext context) {
|
||||
IrisDimensionCarvingResolver.State carvingState = new IrisDimensionCarvingResolver.State();
|
||||
if (k.getSpawnChance() < rng.d())
|
||||
return;
|
||||
|
||||
@@ -123,6 +125,29 @@ public class IrisDepositModifier extends EngineAssignedModifier<PlatformBlockSta
|
||||
if (y > k.getMaxHeight() || y < k.getMinHeight() || y > height - 2)
|
||||
continue;
|
||||
|
||||
if (k.isOre(getData())) {
|
||||
IrisBiome depositBiome = getEngine().getCaveBiome(
|
||||
(cx << 4) + x, y, (cz << 4) + z, carvingState);
|
||||
|
||||
if (depositBiome != null) {
|
||||
double frequencyMultiplier = depositBiome.getOreDepositFrequencyMultiplier();
|
||||
if (frequencyMultiplier < 1D
|
||||
&& !passesOreFrequency(frequencyMultiplier, rng.d())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double sizeMultiplier = depositBiome.getOreDepositSizeMultiplier();
|
||||
if (sizeMultiplier != 1D) {
|
||||
IrisObject scaledClump = k.getClump(getEngine(), rng, getData(), sizeMultiplier);
|
||||
int scaledDimension = scaledClump.getW();
|
||||
x = clampDepositCenter(x, scaledDimension, 16);
|
||||
y = clampDepositCenter(y, scaledDimension, getEngine().getHeight());
|
||||
z = clampDepositCenter(z, scaledDimension, 16);
|
||||
clump = scaledClump;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IrisDimension dimension = getDimension();
|
||||
|
||||
for (art.arcane.iris.util.common.math.IrisBlockVector j : clump.getBlocks().keys()) {
|
||||
@@ -148,7 +173,8 @@ public class IrisDepositModifier extends EngineAssignedModifier<PlatformBlockSta
|
||||
|
||||
if (chunk.get(nx, ny, nz, MatterCavern.class) == null) {
|
||||
PlatformBlockState ore = clump.getBlocks().get(j);
|
||||
PlatformBlockState remapped = resolveDepositVariant(cx, cz, nx, ny, nz, ore, dimension, context);
|
||||
PlatformBlockState remapped = resolveDepositVariant(
|
||||
cx, cz, nx, ny, nz, ore, dimension, context, carvingState);
|
||||
PlatformBlockState finalBlock = remapped != null
|
||||
? remapped
|
||||
: B.toDeepSlateOre(current, ore);
|
||||
@@ -177,12 +203,22 @@ public class IrisDepositModifier extends EngineAssignedModifier<PlatformBlockSta
|
||||
return state != null && !state.isAir() && !state.isFluid();
|
||||
}
|
||||
|
||||
private PlatformBlockState resolveDepositVariant(int cx, int cz, int nx, int localY, int nz, PlatformBlockState ore, IrisDimension dimension, ChunkContext context) {
|
||||
static boolean passesOreFrequency(double multiplier, double sample) {
|
||||
return multiplier >= 1D || sample < Math.max(0D, multiplier);
|
||||
}
|
||||
|
||||
static int clampDepositCenter(int center, int dimension, int limit) {
|
||||
int minimum = dimension / 2;
|
||||
int maximum = (int) (limit - dimension / 2D);
|
||||
return Math.max(minimum, Math.min(center, maximum));
|
||||
}
|
||||
|
||||
private PlatformBlockState resolveDepositVariant(int cx, int cz, int nx, int localY, int nz, PlatformBlockState ore, IrisDimension dimension, ChunkContext context, IrisDimensionCarvingResolver.State carvingState) {
|
||||
int worldX = (cx << 4) + nx;
|
||||
int worldZ = (cz << 4) + nz;
|
||||
int worldY = absoluteWorldY(getEngine().getMinHeight(), localY);
|
||||
|
||||
IrisBiome biome = getEngine().getBiome(worldX, localY, worldZ);
|
||||
IrisBiome biome = getEngine().getCaveBiome(worldX, localY, worldZ, carvingState);
|
||||
if (biome != null) {
|
||||
PlatformBlockState match = matchDepositVariant(biome.getDepositVariants(), ore, worldY);
|
||||
if (match != null) {
|
||||
|
||||
@@ -205,6 +205,14 @@ public class IrisBiome extends IrisRegistrant implements IRare {
|
||||
@ArrayType(min = 1, type = IrisDepositGenerator.class)
|
||||
@Desc("Define biome deposit generators that add onto the existing regional and global deposit generators")
|
||||
private KList<IrisDepositGenerator> deposits = new KList<>();
|
||||
@MinNumber(0)
|
||||
@MaxNumber(1)
|
||||
@Desc("Multiplier applied to the frequency of every ore deposit whose center is inside this biome. A value of 0.4 keeps 40% of ore veins while leaving non-ore deposits unchanged.")
|
||||
private double oreDepositFrequencyMultiplier = 1D;
|
||||
@MinNumber(0.01)
|
||||
@MaxNumber(16)
|
||||
@Desc("Multiplier applied to the block count of every ore deposit whose center is inside this biome. Non-ore deposits are unchanged.")
|
||||
private double oreDepositSizeMultiplier = 1D;
|
||||
@ArrayType(min = 1, type = IrisDepositVariant.class)
|
||||
@Desc("Deposit ore remap rules scoped to this biome. Each entry declares a vertical band and a source->replacement block id map. Applied before regional and dimension rules; first matching biome rule wins.")
|
||||
private KList<IrisDepositVariant> depositVariants = new KList<>();
|
||||
|
||||
@@ -27,16 +27,18 @@ import art.arcane.iris.engine.object.annotations.MaxNumber;
|
||||
import art.arcane.iris.engine.object.annotations.MinNumber;
|
||||
import art.arcane.iris.engine.object.annotations.Required;
|
||||
import art.arcane.iris.engine.object.annotations.Snippet;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.common.math.IrisBlockVector;
|
||||
import art.arcane.iris.util.common.math.Vector3i;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.collection.KSet;
|
||||
import art.arcane.volmlib.util.math.BlockPosition;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Snippet("deposit")
|
||||
@@ -46,8 +48,10 @@ import lombok.experimental.Accessors;
|
||||
@Desc("Creates ore & other block deposits underground")
|
||||
@Data
|
||||
public class IrisDepositGenerator {
|
||||
private final transient AtomicCache<KList<IrisObject>> objects = new AtomicCache<>();
|
||||
private final transient ConcurrentMap<ClumpCacheKey, KList<IrisObject>> objects = new ConcurrentHashMap<>();
|
||||
private final transient AtomicCache<KList<PlatformBlockState>> blockData = new AtomicCache<>();
|
||||
private final transient AtomicCache<Boolean> ore = new AtomicCache<>();
|
||||
private final transient ConcurrentMap<ClumpCacheKey, KList<IrisObject>> scaledObjects = new ConcurrentHashMap<>();
|
||||
@Required
|
||||
@MinNumber(0)
|
||||
@MaxNumber(8192) // TODO: WARNING HEIGHT
|
||||
@@ -98,13 +102,14 @@ public class IrisDepositGenerator {
|
||||
private boolean replaceBedrock = false;
|
||||
|
||||
public IrisObject getClump(Engine engine, RNG rng, IrisData rdata) {
|
||||
KList<IrisObject> objects = this.objects.aquire(() ->
|
||||
{
|
||||
RNG rngv = new RNG(engine.getSeedManager().getDeposit() + hashCode());
|
||||
ClumpCacheKey cacheKey = new ClumpCacheKey(engine.getSeedManager().getDeposit(), minSize, maxSize);
|
||||
KList<IrisObject> objects = this.objects.computeIfAbsent(cacheKey, key -> {
|
||||
RNG rngv = new RNG(key.depositSeed() + hashCode());
|
||||
KList<IrisObject> objectsf = new KList<>();
|
||||
|
||||
for (int i = 0; i < varience; i++) {
|
||||
objectsf.add(generateClumpObject(rngv.nextParallelRNG(2349 * i + 3598), rdata));
|
||||
objectsf.add(generateClumpObject(
|
||||
rngv.nextParallelRNG(2349 * i + 3598), rdata, key.minSize(), key.maxSize()));
|
||||
}
|
||||
|
||||
return objectsf;
|
||||
@@ -112,12 +117,40 @@ public class IrisDepositGenerator {
|
||||
return objects.get(rng.i(0, objects.size()));
|
||||
}
|
||||
|
||||
public IrisObject getClump(Engine engine, RNG rng, IrisData rdata, double sizeMultiplier) {
|
||||
if (sizeMultiplier == 1D) {
|
||||
return getClump(engine, rng, rdata);
|
||||
}
|
||||
|
||||
int scaledMinSize = scaledDepositSize(minSize, sizeMultiplier);
|
||||
int scaledMaxSize = scaledDepositSize(maxSize, sizeMultiplier);
|
||||
ClumpCacheKey cacheKey = new ClumpCacheKey(
|
||||
engine.getSeedManager().getDeposit(), scaledMinSize, scaledMaxSize);
|
||||
KList<IrisObject> objects = scaledObjects.computeIfAbsent(cacheKey, key -> {
|
||||
long sizeSeed = ((long) key.minSize() << 32) ^ (key.maxSize() & 0xffffffffL);
|
||||
RNG rngv = new RNG(key.depositSeed() + hashCode() + sizeSeed);
|
||||
KList<IrisObject> generated = new KList<>();
|
||||
|
||||
for (int i = 0; i < varience; i++) {
|
||||
generated.add(generateClumpObject(
|
||||
rngv.nextParallelRNG(2349 * i + 3598), rdata, key.minSize(), key.maxSize()));
|
||||
}
|
||||
|
||||
return generated;
|
||||
});
|
||||
return objects.get(rng.i(0, objects.size()));
|
||||
}
|
||||
|
||||
public int getMaxDimension() {
|
||||
return Math.min(11, (int) Math.ceil(Math.cbrt(maxSize)));
|
||||
}
|
||||
|
||||
private IrisObject generateClumpObject(RNG rngv, IrisData rdata) {
|
||||
int s = rngv.i(minSize, maxSize + 1);
|
||||
static int scaledDepositSize(int size, double multiplier) {
|
||||
return Math.max(0, Math.min(8192, (int) Math.round(size * multiplier)));
|
||||
}
|
||||
|
||||
private IrisObject generateClumpObject(RNG rngv, IrisData rdata, int clumpMinSize, int clumpMaxSize) {
|
||||
int s = rngv.i(clumpMinSize, clumpMaxSize + 1);
|
||||
if (s == 1) {
|
||||
IrisObject o = new IrisObject(1, 1, 1);
|
||||
Vector3i center = o.getCenter();
|
||||
@@ -184,4 +217,19 @@ public class IrisDepositGenerator {
|
||||
return blockData;
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isOre(IrisData rdata) {
|
||||
return ore.aquire(() -> {
|
||||
for (PlatformBlockState block : getBlockData(rdata)) {
|
||||
if (block.isOre()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
record ClumpCacheKey(long depositSeed, int minSize, int maxSize) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@@ -100,7 +101,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
protected transient volatile boolean smartBored = false;
|
||||
@Setter
|
||||
protected transient AtomicCache<AxisAlignedBB> aabb = new AtomicCache<>();
|
||||
private transient final AtomicCache<Boolean> treeBlockPresence = new AtomicCache<>();
|
||||
private transient final AtomicCache<KList<IrisBlockVector>> surfaceSupportOffsets = new AtomicCache<>();
|
||||
@Getter
|
||||
private VectorMap<PlatformBlockState> blocks;
|
||||
@Getter
|
||||
@@ -326,7 +327,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
public void readLegacy(InputStream in) throws IOException {
|
||||
treeBlockPresence.reset();
|
||||
surfaceSupportOffsets.reset();
|
||||
DataInputStream din = new DataInputStream(in);
|
||||
this.w = din.readInt();
|
||||
this.h = din.readInt();
|
||||
@@ -358,7 +359,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
public void read(InputStream in) throws Throwable {
|
||||
treeBlockPresence.reset();
|
||||
surfaceSupportOffsets.reset();
|
||||
DataInputStream din = new DataInputStream(in);
|
||||
this.w = din.readInt();
|
||||
this.h = din.readInt();
|
||||
@@ -602,6 +603,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
shrinkOffset = offset;
|
||||
blocks = b;
|
||||
states = s;
|
||||
surfaceSupportOffsets.reset();
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
@@ -613,6 +615,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
|
||||
blocks = d;
|
||||
states = dx;
|
||||
surfaceSupportOffsets.reset();
|
||||
}
|
||||
|
||||
public IrisBlockVector getSigned(int x, int y, int z) {
|
||||
@@ -624,7 +627,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
public void setUnsigned(int x, int y, int z, PlatformBlockState block) {
|
||||
treeBlockPresence.reset();
|
||||
surfaceSupportOffsets.reset();
|
||||
IrisBlockVector v = getSigned(x, y, z);
|
||||
|
||||
if (block == null) {
|
||||
@@ -646,7 +649,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
public void setUnsigned(int x, int y, int z, Block block, boolean legacy) {
|
||||
treeBlockPresence.reset();
|
||||
surfaceSupportOffsets.reset();
|
||||
IrisBlockVector v = getSigned(x, y, z);
|
||||
|
||||
if (block == null) {
|
||||
@@ -932,9 +935,8 @@ public class IrisObject extends IrisRegistrant {
|
||||
&& !config.isUnderwater()
|
||||
&& !config.isOnwater()
|
||||
&& config.getCarvingSupport().supportsSurface()
|
||||
&& hasTreeBlocks()
|
||||
&& IrisSurfaceOpening.isOpen(oplacer, getLoader(), x, z, config.getTranslate(),
|
||||
config.getRotation(), spinx, spiny, spinz)) {
|
||||
config.getRotation(), spinx, spiny, spinz, getSurfaceSupportOffsets())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1511,16 +1513,32 @@ public class IrisObject extends IrisRegistrant {
|
||||
};
|
||||
}
|
||||
|
||||
boolean hasTreeBlocks() {
|
||||
Boolean present = treeBlockPresence.aquire(() -> {
|
||||
KList<IrisBlockVector> getSurfaceSupportOffsets() {
|
||||
return surfaceSupportOffsets.aquire(() -> {
|
||||
readLock.lock();
|
||||
try {
|
||||
return IrisSurfaceOpening.containsTreeBlocks(blocks.values());
|
||||
int lowestY = Integer.MAX_VALUE;
|
||||
KList<IrisBlockVector> offsets = new KList<>();
|
||||
for (Map.Entry<IrisBlockVector, PlatformBlockState> entry : blocks) {
|
||||
PlatformBlockState state = entry.getValue();
|
||||
if (state == null || !state.isSolid() || state.isFoliage()) {
|
||||
continue;
|
||||
}
|
||||
IrisBlockVector position = entry.getKey();
|
||||
int blockY = position.getBlockY();
|
||||
if (blockY < lowestY) {
|
||||
lowestY = blockY;
|
||||
offsets.clear();
|
||||
}
|
||||
if (blockY == lowestY) {
|
||||
offsets.add(position.clone());
|
||||
}
|
||||
}
|
||||
return offsets;
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
});
|
||||
return Boolean.TRUE.equals(present);
|
||||
}
|
||||
|
||||
private boolean isCarvedCaveAnchor(IObjectPlacer placer, int x, int y, int z) {
|
||||
@@ -1584,6 +1602,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
|
||||
blocks = d;
|
||||
states = dx;
|
||||
surfaceSupportOffsets.reset();
|
||||
shrinkwrap();
|
||||
writeLock.unlock();
|
||||
}
|
||||
@@ -1713,6 +1732,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
blocks = b;
|
||||
surfaceSupportOffsets.reset();
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
@@ -1744,6 +1764,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
blocks = b;
|
||||
surfaceSupportOffsets.reset();
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
@@ -1779,6 +1800,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
blocks = b;
|
||||
surfaceSupportOffsets.reset();
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,4 +21,7 @@ public class IrisStructureStiltSettings {
|
||||
|
||||
@Desc("Block palette used for foundation columns.")
|
||||
private IrisMaterialPalette palette = new IrisMaterialPalette().qclear().qadd("minecraft:cobblestone");
|
||||
|
||||
@Desc("For Iris-authored structures, whether solid partial blocks such as slabs, stairs, and walls may seed foundation columns instead of requiring a fully occluding base block.")
|
||||
private boolean supportNonOccluding = false;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package art.arcane.iris.engine.object;
|
||||
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.common.math.IrisBlockVector;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
final class IrisSurfaceOpening {
|
||||
private static final int SUPPORT_RADIUS = 1;
|
||||
|
||||
@@ -11,15 +12,37 @@ final class IrisSurfaceOpening {
|
||||
}
|
||||
|
||||
static boolean isOpen(IObjectPlacer placer, IrisData data, int x, int z, IrisObjectTranslate translate,
|
||||
IrisObjectRotation rotation, int spinX, int spinY, int spinZ) {
|
||||
IrisBlockVector offset = new IrisBlockVector(0, 0, 0);
|
||||
if (translate != null) {
|
||||
offset = rotation == null
|
||||
? translate.translate(offset)
|
||||
: translate.translate(offset, rotation, spinX, spinY, spinZ);
|
||||
IrisObjectRotation rotation, int spinX, int spinY, int spinZ,
|
||||
List<IrisBlockVector> supportOffsets) {
|
||||
if (supportOffsets.isEmpty()) {
|
||||
IrisBlockVector origin = transform(new IrisBlockVector(0, 0, 0), translate, rotation, spinX, spinY, spinZ);
|
||||
return isOpenAround(placer, data, x + origin.getBlockX(), z + origin.getBlockZ());
|
||||
}
|
||||
int centerX = x + offset.getBlockX();
|
||||
int centerZ = z + offset.getBlockZ();
|
||||
|
||||
for (IrisBlockVector supportOffset : supportOffsets) {
|
||||
IrisBlockVector transformed = transform(supportOffset, translate, rotation, spinX, spinY, spinZ);
|
||||
if (isOpenAround(placer, data, x + transformed.getBlockX(), z + transformed.getBlockZ())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static IrisBlockVector transform(IrisBlockVector offset, IrisObjectTranslate translate,
|
||||
IrisObjectRotation rotation, int spinX, int spinY, int spinZ) {
|
||||
IrisBlockVector transformed = offset.clone();
|
||||
if (rotation != null) {
|
||||
transformed = rotation.rotate(transformed, spinX, spinY, spinZ);
|
||||
}
|
||||
if (translate == null) {
|
||||
return transformed;
|
||||
}
|
||||
return rotation == null
|
||||
? translate.translate(transformed)
|
||||
: translate.translate(transformed, rotation, spinX, spinY, spinZ);
|
||||
}
|
||||
|
||||
private static boolean isOpenAround(IObjectPlacer placer, IrisData data, int centerX, int centerZ) {
|
||||
for (int dx = -SUPPORT_RADIUS; dx <= SUPPORT_RADIUS; dx++) {
|
||||
for (int dz = -SUPPORT_RADIUS; dz <= SUPPORT_RADIUS; dz++) {
|
||||
int sampleX = centerX + dx;
|
||||
@@ -32,13 +55,4 @@ final class IrisSurfaceOpening {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean containsTreeBlocks(Iterable<PlatformBlockState> states) {
|
||||
for (PlatformBlockState state : states) {
|
||||
if (state != null && state.isTreeBlock()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ public class SchemaBuilderParityTest {
|
||||
assertTrue(properties.has("distribution"));
|
||||
assertEquals("object", stilt.getString("type"));
|
||||
assertTrue(stiltProperties.has("palette"));
|
||||
assertTrue(stiltProperties.has("supportNonOccluding"));
|
||||
assertEquals(1, maxDepth.getInt("minimum"));
|
||||
assertEquals(4064, maxDepth.getInt("maximum"));
|
||||
assertFalse(properties.has("rotation"));
|
||||
|
||||
@@ -2,6 +2,7 @@ package art.arcane.iris.engine.decorator;
|
||||
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisBlockData;
|
||||
import art.arcane.iris.engine.object.IrisDecorationPart;
|
||||
import art.arcane.iris.engine.object.IrisDecorator;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
@@ -378,6 +379,31 @@ public class DecoratorCoreTest {
|
||||
assertSame(upper, output.get(0, 2, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forcedSurfaceBlockStillPlacesDecorantAboveIt() {
|
||||
IrisDecorator decorator = mock(IrisDecorator.class);
|
||||
IrisBlockData forcedBlock = mock(IrisBlockData.class);
|
||||
IrisData data = mock(IrisData.class);
|
||||
PlatformBlockState support = sturdyState();
|
||||
PlatformBlockState farmland = sturdyState();
|
||||
PlatformBlockState air = airState();
|
||||
PlatformBlockState wheat = mock(PlatformBlockState.class);
|
||||
when(wheat.key()).thenReturn("minecraft:wheat[age=7]");
|
||||
when(decorator.getForceBlock()).thenReturn(forcedBlock);
|
||||
when(forcedBlock.getBlockData(data)).thenReturn(farmland);
|
||||
when(decorator.pickBlockData(any(RNG.class), eq(data), anyDouble(), anyDouble())).thenReturn(wheat);
|
||||
|
||||
Hunk<PlatformBlockState> output = Hunk.newArrayHunk(1, 3, 1);
|
||||
output.set(0, 0, 0, support);
|
||||
output.set(0, 1, 0, air);
|
||||
|
||||
DecoratorCore.placeSurfaceSingle(
|
||||
decorator, 0, 0, 0, 0, 0, output, new RNG(1L), data, false, false, null);
|
||||
|
||||
assertSame(farmland, output.get(0, 0, 0));
|
||||
assertSame(wheat, output.get(0, 1, 0));
|
||||
}
|
||||
|
||||
private PlatformBlockState airState() {
|
||||
PlatformBlockState air = mock(PlatformBlockState.class);
|
||||
when(air.isAir()).thenReturn(true);
|
||||
|
||||
+33
-7
@@ -15,26 +15,52 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
public class StructureFoundationPlannerTest {
|
||||
@Test
|
||||
public void recordsLowestPlacedOccludingCellAcrossTheAssembledFootprint() {
|
||||
public void recordsLowestPlacedOccludingCellByDefault() {
|
||||
PlatformBlockState solid = mock(PlatformBlockState.class);
|
||||
when(solid.isOccluding()).thenReturn(true);
|
||||
when(solid.isSolid()).thenReturn(true);
|
||||
PlatformBlockState nonOccludingSolid = mock(PlatformBlockState.class);
|
||||
when(nonOccludingSolid.isSolid()).thenReturn(true);
|
||||
when(nonOccludingSolid.isOccluding()).thenReturn(false);
|
||||
PlatformBlockState decoration = mock(PlatformBlockState.class);
|
||||
when(decoration.isOccluding()).thenReturn(false);
|
||||
|
||||
Long2IntOpenHashMap columns = new Long2IntOpenHashMap();
|
||||
StructureFoundationPlanner.recordBaseCell(columns, 100, 48, 200, decoration);
|
||||
StructureFoundationPlanner.recordBaseCell(columns, 100, 49, 200, solid);
|
||||
StructureFoundationPlanner.recordBaseCell(columns, 100, 50, 200, solid);
|
||||
StructureFoundationPlanner.recordBaseCell(columns, 100, 45, 200, solid);
|
||||
StructureFoundationPlanner.recordBaseCell(columns, -17, 60, -33, solid);
|
||||
StructureFoundationPlanner.recordBaseCell(columns, 100, 48, 200, decoration, false);
|
||||
StructureFoundationPlanner.recordBaseCell(columns, 100, 49, 200, solid, false);
|
||||
StructureFoundationPlanner.recordBaseCell(columns, 100, 50, 200, solid, false);
|
||||
StructureFoundationPlanner.recordBaseCell(columns, 100, 45, 200, solid, false);
|
||||
StructureFoundationPlanner.recordBaseCell(columns, -17, 60, -33, solid, false);
|
||||
StructureFoundationPlanner.recordBaseCell(columns, 12, 41, 44, solid, false);
|
||||
StructureFoundationPlanner.recordBaseCell(columns, 12, 36, 44, nonOccludingSolid, false);
|
||||
|
||||
assertEquals(2, columns.size());
|
||||
assertEquals(3, columns.size());
|
||||
assertEquals(45, columns.get(StructureFoundationPlanner.pack(100, 200)));
|
||||
assertEquals(60, columns.get(StructureFoundationPlanner.pack(-17, -33)));
|
||||
assertEquals(41, columns.get(StructureFoundationPlanner.pack(12, 44)));
|
||||
assertEquals(-17, StructureFoundationPlanner.unpackX(StructureFoundationPlanner.pack(-17, -33)));
|
||||
assertEquals(-33, StructureFoundationPlanner.unpackZ(StructureFoundationPlanner.pack(-17, -33)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recordsSolidNonOccludingBaseWhenEnabled() {
|
||||
PlatformBlockState partialStructureBlock = mock(PlatformBlockState.class);
|
||||
when(partialStructureBlock.isSolid()).thenReturn(true);
|
||||
when(partialStructureBlock.isOccluding()).thenReturn(false);
|
||||
PlatformBlockState fullStructureBlock = mock(PlatformBlockState.class);
|
||||
when(fullStructureBlock.isSolid()).thenReturn(true);
|
||||
when(fullStructureBlock.isOccluding()).thenReturn(true);
|
||||
|
||||
Long2IntOpenHashMap columns = new Long2IntOpenHashMap();
|
||||
StructureFoundationPlanner.recordBaseCell(
|
||||
columns, 12, 41, 44, fullStructureBlock, true);
|
||||
StructureFoundationPlanner.recordBaseCell(
|
||||
columns, 12, 36, 44, partialStructureBlock, true);
|
||||
|
||||
assertEquals(1, columns.size());
|
||||
assertEquals(36, columns.get(StructureFoundationPlanner.pack(12, 44)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scansThroughAirAndFluidUntilSolidGround() {
|
||||
int groundY = StructureFoundationPlanner.findGroundY(10, 10, 0, y -> y == 3);
|
||||
|
||||
+17
@@ -53,4 +53,21 @@ public class IrisDepositModifierContainmentTest {
|
||||
assertFalse(IrisDepositModifier.canReplaceDepositTarget(fluid));
|
||||
assertFalse(IrisDepositModifier.canReplaceDepositTarget(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oreFrequencyMultiplierKeepsConfiguredShareOfVeins() {
|
||||
assertTrue(IrisDepositModifier.passesOreFrequency(0.4D, 0.399D));
|
||||
assertFalse(IrisDepositModifier.passesOreFrequency(0.4D, 0.4D));
|
||||
assertTrue(IrisDepositModifier.passesOreFrequency(1D, 0.999D));
|
||||
assertFalse(IrisDepositModifier.passesOreFrequency(0D, 0D));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void largerVeinsRemainCenteredAndInsideTheChunk() {
|
||||
assertEquals(6, IrisDepositModifier.clampDepositCenter(6, 5, 16));
|
||||
assertEquals(2, IrisDepositModifier.clampDepositCenter(1, 5, 16));
|
||||
assertEquals(13, IrisDepositModifier.clampDepositCenter(14, 5, 16));
|
||||
assertEquals(2, IrisDepositModifier.clampDepositCenter(1, 4, 16));
|
||||
assertEquals(14, IrisDepositModifier.clampDepositCenter(15, 4, 16));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package art.arcane.iris.engine.object;
|
||||
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class IrisDepositTuningTest {
|
||||
@Test
|
||||
public void depositSizesScaleAndRemainWithinSchemaLimit() {
|
||||
assertEquals(8, IrisDepositGenerator.scaledDepositSize(4, 2D));
|
||||
assertEquals(16, IrisDepositGenerator.scaledDepositSize(8, 2D));
|
||||
assertEquals(0, IrisDepositGenerator.scaledDepositSize(0, 2D));
|
||||
assertEquals(8192, IrisDepositGenerator.scaledDepositSize(8192, 2D));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void biomeOreTuningDefaultsPreserveExistingGeneration() {
|
||||
IrisBiome biome = new IrisBiome();
|
||||
|
||||
assertEquals(1D, biome.getOreDepositFrequencyMultiplier(), 0D);
|
||||
assertEquals(1D, biome.getOreDepositSizeMultiplier(), 0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clumpCachesAreScopedByWorldSeedAndSize() {
|
||||
IrisDepositGenerator.ClumpCacheKey firstWorld =
|
||||
new IrisDepositGenerator.ClumpCacheKey(41L, 4, 8);
|
||||
IrisDepositGenerator.ClumpCacheKey secondWorld =
|
||||
new IrisDepositGenerator.ClumpCacheKey(42L, 4, 8);
|
||||
IrisDepositGenerator.ClumpCacheKey largerVein =
|
||||
new IrisDepositGenerator.ClumpCacheKey(41L, 8, 16);
|
||||
|
||||
assertNotEquals(firstWorld, secondWorld);
|
||||
assertNotEquals(firstWorld, largerVein);
|
||||
assertEquals(firstWorld, new IrisDepositGenerator.ClumpCacheKey(41L, 4, 8));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onlyOreDepositPalettesReceiveBiomeTuning() {
|
||||
IrisData data = mock(IrisData.class);
|
||||
IrisDepositGenerator oreGenerator = generatorWithState(data, true);
|
||||
IrisDepositGenerator stoneGenerator = generatorWithState(data, false);
|
||||
|
||||
assertTrue(oreGenerator.isOre(data));
|
||||
assertFalse(stoneGenerator.isOre(data));
|
||||
}
|
||||
|
||||
private IrisDepositGenerator generatorWithState(IrisData data, boolean ore) {
|
||||
IrisBlockData block = mock(IrisBlockData.class);
|
||||
PlatformBlockState state = mock(PlatformBlockState.class);
|
||||
when(block.getBlockData(data)).thenReturn(state);
|
||||
when(state.isOre()).thenReturn(ore);
|
||||
IrisDepositGenerator generator = new IrisDepositGenerator();
|
||||
generator.getPalette().add(block);
|
||||
return generator;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import org.junit.Test;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
public class IrisStructureStiltSettingsTest {
|
||||
@@ -15,6 +16,7 @@ public class IrisStructureStiltSettingsTest {
|
||||
IrisStructureStiltSettings settings = new IrisStructureStiltSettings();
|
||||
|
||||
assertEquals(64, settings.getMaxDepth());
|
||||
assertFalse(settings.isSupportNonOccluding());
|
||||
assertNotNull(settings.getPalette());
|
||||
assertEquals(1, settings.getPalette().getPalette().size());
|
||||
assertEquals("minecraft:cobblestone", settings.getPalette().getPalette().get(0).getBlock());
|
||||
|
||||
@@ -3,6 +3,7 @@ package art.arcane.iris.engine.object;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.common.math.IrisBlockVector;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -23,7 +24,8 @@ public class IrisSurfaceOpeningTest {
|
||||
SurfacePlacer placer = new SurfacePlacer(80);
|
||||
placer.carve(1, 80, 1);
|
||||
|
||||
assertTrue(IrisSurfaceOpening.isOpen(placer, null, 0, 0, null, null, 0, 0, 0));
|
||||
assertTrue(IrisSurfaceOpening.isOpen(placer, null, 0, 0, null, null, 0, 0, 0,
|
||||
List.of(new IrisBlockVector(0, 0, 0))));
|
||||
assertEquals(9, placer.heightQueries());
|
||||
}
|
||||
|
||||
@@ -34,7 +36,8 @@ public class IrisSurfaceOpeningTest {
|
||||
placer.carve(0, 78, 0);
|
||||
placer.carve(0, 77, 0);
|
||||
|
||||
assertFalse(IrisSurfaceOpening.isOpen(placer, null, 0, 0, null, null, 0, 0, 0));
|
||||
assertFalse(IrisSurfaceOpening.isOpen(placer, null, 0, 0, null, null, 0, 0, 0,
|
||||
List.of(new IrisBlockVector(0, 0, 0))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -47,7 +50,8 @@ public class IrisSurfaceOpeningTest {
|
||||
}
|
||||
placer.carve(1, 82, 1);
|
||||
|
||||
assertTrue(IrisSurfaceOpening.isOpen(placer, null, 0, 0, null, null, 0, 0, 0));
|
||||
assertTrue(IrisSurfaceOpening.isOpen(placer, null, 0, 0, null, null, 0, 0, 0,
|
||||
List.of(new IrisBlockVector(0, 0, 0))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -55,36 +59,63 @@ public class IrisSurfaceOpeningTest {
|
||||
SurfacePlacer placer = new SurfacePlacer(80);
|
||||
placer.carve(2, 80, 0);
|
||||
|
||||
assertFalse(IrisSurfaceOpening.isOpen(placer, null, 0, 0, null, null, 0, 0, 0));
|
||||
assertFalse(IrisSurfaceOpening.isOpen(placer, null, 0, 0, null, null, 0, 0, 0,
|
||||
List.of(new IrisBlockVector(0, 0, 0))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placementTranslationMovesSupportStencil() {
|
||||
public void offsetSupportFootprintMovesSupportStencil() {
|
||||
SurfacePlacer placer = new SurfacePlacer(80);
|
||||
IrisObjectTranslate translate = new IrisObjectTranslate().setX(5).setZ(-3);
|
||||
placer.carve(5, 80, -3);
|
||||
|
||||
assertTrue(IrisSurfaceOpening.isOpen(placer, null, 0, 0, translate, null, 0, 0, 0));
|
||||
assertTrue(IrisSurfaceOpening.isOpen(placer, null, 0, 0, null, null, 0, 0, 0,
|
||||
List.of(new IrisBlockVector(5, 0, -3))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placementTranslationUsesTheSameRotationAsObjectBlocks() {
|
||||
public void placementTranslationAndRotationMatchObjectBlocks() {
|
||||
SurfacePlacer placer = new SurfacePlacer(80);
|
||||
IrisObjectTranslate translate = new IrisObjectTranslate().setX(5).setZ(-3);
|
||||
IrisObjectRotation rotation = IrisObjectRotation.of(0, 90, 0);
|
||||
placer.carve(-3, 80, -5);
|
||||
placer.carve(-3, 80, -7);
|
||||
|
||||
assertTrue(IrisSurfaceOpening.isOpen(placer, null, 0, 0, translate, rotation, 0, 0, 0));
|
||||
assertTrue(IrisSurfaceOpening.isOpen(placer, null, 0, 0, translate, rotation, 0, 0, 0,
|
||||
List.of(new IrisBlockVector(2, 0, 0))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void treeBlockClassificationDoesNotMatchUnrelatedObjects() {
|
||||
PlatformBlockState stone = mock(PlatformBlockState.class);
|
||||
PlatformBlockState log = mock(PlatformBlockState.class);
|
||||
when(log.isTreeBlock()).thenReturn(true);
|
||||
public void emptyFootprintFallsBackToPlacementOrigin() {
|
||||
SurfacePlacer placer = new SurfacePlacer(80);
|
||||
IrisObjectTranslate translate = new IrisObjectTranslate().setX(4).setZ(-2);
|
||||
placer.carve(4, 80, -2);
|
||||
|
||||
assertFalse(IrisSurfaceOpening.containsTreeBlocks(List.of(stone)));
|
||||
assertTrue(IrisSurfaceOpening.containsTreeBlocks(List.of(stone, log)));
|
||||
assertTrue(IrisSurfaceOpening.isOpen(placer, null, 0, 0, translate, null, 0, 0, 0, List.of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void objectCachesItsLowestNonFoliageSupportBlocks() {
|
||||
PlatformBlockState solid = mock(PlatformBlockState.class);
|
||||
PlatformBlockState foliage = mock(PlatformBlockState.class);
|
||||
when(solid.isSolid()).thenReturn(true);
|
||||
when(foliage.isSolid()).thenReturn(true);
|
||||
when(foliage.isFoliage()).thenReturn(true);
|
||||
|
||||
IrisObject object = new IrisObject(9, 9, 9);
|
||||
object.setUnsigned(7, 1, 4, solid);
|
||||
object.setUnsigned(4, 0, 4, foliage);
|
||||
object.setUnsigned(4, 5, 4, solid);
|
||||
|
||||
List<IrisBlockVector> initial = object.getSurfaceSupportOffsets();
|
||||
assertEquals(1, initial.size());
|
||||
assertEquals(3, initial.getFirst().getBlockX());
|
||||
assertEquals(-3, initial.getFirst().getBlockY());
|
||||
|
||||
object.setUnsigned(2, 0, 4, solid);
|
||||
|
||||
List<IrisBlockVector> updated = object.getSurfaceSupportOffsets();
|
||||
assertEquals(1, updated.size());
|
||||
assertEquals(-2, updated.getFirst().getBlockX());
|
||||
assertEquals(-4, updated.getFirst().getBlockY());
|
||||
}
|
||||
|
||||
private static final class SurfacePlacer implements IObjectPlacer {
|
||||
|
||||
Reference in New Issue
Block a user