1979 lines
75 KiB
Java
1979 lines
75 KiB
Java
package com.boydti.fawe.object.brush.visualization.cfi;
|
|
|
|
import com.boydti.fawe.Fawe;
|
|
import com.boydti.fawe.FaweCache;
|
|
import com.boydti.fawe.beta.IChunkGet;
|
|
import com.boydti.fawe.beta.IQueueExtent;
|
|
import com.boydti.fawe.beta.implementation.FallbackChunkGet;
|
|
import com.boydti.fawe.object.FaweInputStream;
|
|
import com.boydti.fawe.object.FaweOutputStream;
|
|
import com.boydti.fawe.object.FawePlayer;
|
|
import com.boydti.fawe.object.Metadatable;
|
|
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
|
import com.boydti.fawe.object.change.StreamChange;
|
|
import com.boydti.fawe.object.changeset.CFIChangeSet;
|
|
import com.boydti.fawe.object.collection.DifferentialArray;
|
|
import com.boydti.fawe.object.collection.DifferentialBlockBuffer;
|
|
import com.boydti.fawe.object.collection.LocalBlockVector2DSet;
|
|
import com.boydti.fawe.object.collection.SummedAreaTable;
|
|
import com.boydti.fawe.object.exception.FaweException;
|
|
import com.boydti.fawe.object.schematic.Schematic;
|
|
import com.boydti.fawe.util.CachedTextureUtil;
|
|
import com.boydti.fawe.util.RandomTextureUtil;
|
|
import com.boydti.fawe.util.ReflectionUtils;
|
|
import com.boydti.fawe.util.TextureUtil;
|
|
import com.boydti.fawe.util.image.Drawable;
|
|
import com.boydti.fawe.util.image.ImageViewer;
|
|
import com.sk89q.jnbt.CompoundTag;
|
|
import com.sk89q.worldedit.EditSession;
|
|
import com.sk89q.worldedit.LocalSession;
|
|
import com.sk89q.worldedit.WorldEditException;
|
|
import com.sk89q.worldedit.blocks.BaseItemStack;
|
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
|
import com.sk89q.worldedit.function.mask.Mask;
|
|
import com.sk89q.worldedit.function.operation.Operation;
|
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
|
import com.sk89q.worldedit.math.BlockVector2;
|
|
import com.sk89q.worldedit.math.BlockVector3;
|
|
import com.sk89q.worldedit.math.MutableBlockVector3;
|
|
import com.sk89q.worldedit.math.Vector3;
|
|
import com.sk89q.worldedit.math.transform.AffineTransform;
|
|
import com.sk89q.worldedit.math.transform.Transform;
|
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
|
import com.sk89q.worldedit.regions.Region;
|
|
import com.sk89q.worldedit.registry.state.PropertyKey;
|
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
|
import com.sk89q.worldedit.util.Location;
|
|
import com.sk89q.worldedit.world.World;
|
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
|
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
|
import com.sk89q.worldedit.world.block.BlockID;
|
|
import com.sk89q.worldedit.world.block.BlockState;
|
|
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
|
import com.sk89q.worldedit.world.block.BlockType;
|
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
|
|
|
import javax.annotation.Nullable;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.File;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.IOException;
|
|
import java.lang.reflect.Field;
|
|
import java.nio.file.Path;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.ThreadLocalRandom;
|
|
|
|
// TODO FIXME
|
|
public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Drawable, VirtualWorld {
|
|
private final MutableBlockVector3 mutable = new MutableBlockVector3();
|
|
|
|
private final DifferentialBlockBuffer blocks;
|
|
protected final DifferentialArray<byte[]> heights;
|
|
protected final DifferentialArray<byte[]> biomes;
|
|
protected final DifferentialArray<int[]> floor;
|
|
protected final DifferentialArray<int[]> main;
|
|
protected DifferentialArray<int[]> overlay;
|
|
|
|
protected final CFIPrimitives primitives = new CFIPrimitives();
|
|
private CFIPrimitives oldPrimitives = new CFIPrimitives();
|
|
|
|
public final class CFIPrimitives implements Cloneable {
|
|
protected int waterHeight = 0;
|
|
protected int floorThickness = 0;
|
|
protected int worldThickness = 0;
|
|
protected boolean randomVariation = true;
|
|
protected int biomePriority = 0;
|
|
protected int waterId = BlockID.WATER;
|
|
protected int bedrockId = BlockID.BEDROCK;
|
|
protected boolean modifiedMain = false;
|
|
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (obj == null || !(obj instanceof CFIPrimitives)) {
|
|
return false;
|
|
}
|
|
try {
|
|
for (Field field : CFIPrimitives.class.getDeclaredFields()) {
|
|
if (field.get(this) != field.get(obj)) return false;
|
|
}
|
|
} catch (IllegalAccessException e) {
|
|
e.printStackTrace();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
protected Object clone() throws CloneNotSupportedException {
|
|
return super.clone();
|
|
}
|
|
}
|
|
|
|
|
|
protected Metadatable metaData = new Metadatable();
|
|
protected TextureUtil textureUtil;
|
|
|
|
@Override
|
|
public void flushChanges(FaweOutputStream out) throws IOException {
|
|
heights.flushChanges(out);
|
|
biomes.flushChanges(out);
|
|
floor.flushChanges(out);
|
|
main.flushChanges(out);
|
|
out.writeBoolean(overlay != null);
|
|
if (overlay != null) overlay.flushChanges(out);
|
|
try {
|
|
for (Field field : ReflectionUtils.sortFields(CFIPrimitives.class.getDeclaredFields())) {
|
|
Object now = field.get(primitives);
|
|
Object old = field.get(oldPrimitives);
|
|
boolean diff = old != now;
|
|
out.writeBoolean(diff);
|
|
if (diff) {
|
|
out.writePrimitive(old);
|
|
out.writePrimitive(now);
|
|
}
|
|
}
|
|
resetPrimitives();
|
|
} catch (Throwable neverHappens) {
|
|
neverHappens.printStackTrace();
|
|
}
|
|
|
|
blocks.flushChanges(out);
|
|
}
|
|
|
|
public boolean isModified() {
|
|
return blocks.isModified() ||
|
|
heights.isModified() ||
|
|
biomes.isModified() ||
|
|
(overlay != null && overlay.isModified()) ||
|
|
!primitives.equals(oldPrimitives);
|
|
}
|
|
|
|
private void resetPrimitives() throws CloneNotSupportedException {
|
|
oldPrimitives = (CFIPrimitives) primitives.clone();
|
|
}
|
|
|
|
@Override
|
|
public void undoChanges(FaweInputStream in) throws IOException {
|
|
heights.undoChanges(in);
|
|
biomes.undoChanges(in);
|
|
floor.undoChanges(in);
|
|
main.undoChanges(in);
|
|
if (in.readBoolean()) overlay.undoChanges(in);
|
|
try {
|
|
for (Field field : ReflectionUtils.sortFields(CFIPrimitives.class.getDeclaredFields())) {
|
|
if (in.readBoolean()) {
|
|
field.set(primitives, in.readPrimitive(field.getType())); // old
|
|
in.readPrimitive(field.getType()); // new
|
|
}
|
|
}
|
|
resetPrimitives();
|
|
} catch (Throwable neverHappens) {
|
|
neverHappens.printStackTrace();
|
|
}
|
|
blocks.undoChanges(in);
|
|
}
|
|
|
|
@Override
|
|
public void redoChanges(FaweInputStream in) throws IOException {
|
|
heights.redoChanges(in);
|
|
biomes.redoChanges(in);
|
|
floor.redoChanges(in);
|
|
main.redoChanges(in);
|
|
if (in.readBoolean()) overlay.redoChanges(in);
|
|
|
|
try {
|
|
for (Field field : ReflectionUtils.sortFields(CFIPrimitives.class.getDeclaredFields())) {
|
|
if (in.readBoolean()) {
|
|
in.readPrimitive(field.getType()); // old
|
|
field.set(primitives, in.readPrimitive(field.getType())); // new
|
|
}
|
|
}
|
|
resetPrimitives();
|
|
} catch (Throwable neverHappens) {
|
|
neverHappens.printStackTrace();
|
|
}
|
|
|
|
blocks.clearChanges(); // blocks.redoChanges(in); Unsupported
|
|
}
|
|
|
|
// @Override TODO NOT IMPLEMENTED
|
|
public void addEditSession(EditSession session) {
|
|
session.setFastMode(true);
|
|
this.editSession = session;
|
|
}
|
|
|
|
// Used for visualizing the world on a map
|
|
private ImageViewer viewer;
|
|
// Used for visualizing the world by sending chunk packets
|
|
// These three variables should be set together
|
|
// private IQueueExtent packetQueue;
|
|
private FawePlayer player;
|
|
private BlockVector2 chunkOffset = BlockVector2.ZERO;
|
|
private EditSession editSession;
|
|
// end
|
|
|
|
public HeightMapMCAGenerator(BufferedImage img, File regionFolder) {
|
|
this(img.getWidth(), img.getHeight(), regionFolder);
|
|
setHeight(img);
|
|
}
|
|
|
|
public HeightMapMCAGenerator(int width, int length, File regionFolder) {
|
|
super(width, length, regionFolder);
|
|
|
|
blocks = new DifferentialBlockBuffer(width, length);
|
|
heights = new DifferentialArray(new byte[getArea()]);
|
|
biomes = new DifferentialArray(new byte[getArea()]);
|
|
floor = new DifferentialArray(new int[getArea()]);
|
|
main = new DifferentialArray(new int[getArea()]);
|
|
|
|
int stone = BlockID.STONE;
|
|
int grass = BlockTypes.GRASS_BLOCK.getDefaultState().with(PropertyKey.SNOWY, false).getInternalId();
|
|
Arrays.fill(main.getIntArray(), stone);
|
|
Arrays.fill(floor.getIntArray(), grass);
|
|
}
|
|
|
|
public Metadatable getMetaData() {
|
|
return metaData;
|
|
}
|
|
|
|
@Override
|
|
public Vector3 getOrigin() {
|
|
return Vector3.at(chunkOffset.getBlockX() << 4, 0, chunkOffset.getBlockZ() << 4);
|
|
}
|
|
|
|
public boolean hasPacketViewer() {
|
|
return player != null;
|
|
}
|
|
|
|
public void setPacketViewer(FawePlayer player) {
|
|
this.player = player;
|
|
if (player != null) {
|
|
Location pos = player.getLocation();
|
|
this.chunkOffset = BlockVector2.at(1 + (pos.getBlockX() >> 4), 1 + (pos.getBlockZ() >> 4));
|
|
}
|
|
}
|
|
|
|
public FawePlayer getOwner() {
|
|
return player;
|
|
}
|
|
|
|
private int[][][] getChunkArray(int x, int z) {
|
|
int[][][][][] blocksData = blocks.get();
|
|
if (blocksData == null) return null;
|
|
int[][][][] arr = blocksData[z];
|
|
return arr != null ? arr[x] : null;
|
|
}
|
|
|
|
public void setImageViewer(ImageViewer viewer) {
|
|
this.viewer = viewer;
|
|
}
|
|
|
|
public ImageViewer getImageViewer() {
|
|
return viewer;
|
|
}
|
|
|
|
@Override
|
|
public void update() {
|
|
if (viewer != null) {
|
|
viewer.view(this);
|
|
}
|
|
// if (chunkOffset != null && player != null) { TODO NOT IMPLEMENTED
|
|
// IQueueExtent packetQueue = SetQueue.IMP.getNewQueue(player.getWorld(), true, false);
|
|
//
|
|
// if (!packetQueue.supports(Capability.CHUNK_PACKETS)) {
|
|
// return;
|
|
// }
|
|
//
|
|
// int lenCX = (getWidth() + 15) >> 4;
|
|
// int lenCZ = (getLength() + 15) >> 4;
|
|
//
|
|
// int OX = chunkOffset.getBlockX();
|
|
// int OZ = chunkOffset.getBlockZ();
|
|
//
|
|
// Location position = player.getLocation();
|
|
// int pcx = (position.getBlockX() >> 4) - OX;
|
|
// int pcz = (position.getBlockZ() >> 4) - OZ;
|
|
//
|
|
// int scx = Math.max(0, pcx - 15);
|
|
// int scz = Math.max(0, pcz - 15);
|
|
// int ecx = Math.min(lenCX - 1, pcx + 15);
|
|
// int ecz = Math.min(lenCZ - 1, pcz + 15);
|
|
//
|
|
// for (int cz = scz; cz <= ecz; cz++) {
|
|
// for (int cx = scx; cx <= ecx; cx++) {
|
|
// final int finalCX = cx;
|
|
// final int finalCZ = cz;
|
|
// TaskManager.IMP.getPublicForkJoinPool().submit(() -> {
|
|
// try {
|
|
// FaweChunk toSend = getSnapshot(finalCX, finalCZ);
|
|
// toSend.setLoc(HeightMapMCAGenerator.this, finalCX + OX, finalCZ + OZ);
|
|
// packetQueue.sendChunkUpdate(toSend, player);
|
|
// } catch (Throwable e) {
|
|
// e.printStackTrace();
|
|
// }
|
|
// });
|
|
// }
|
|
// }
|
|
// }
|
|
}
|
|
|
|
@Override
|
|
public void sendChunk(int X, int Z, int mask) {
|
|
throw new UnsupportedOperationException("TODO NOT IMPLEMENTED"); // add method to adapter to send custom chunk
|
|
}
|
|
|
|
public TextureUtil getRawTextureUtil() {
|
|
if (textureUtil == null) {
|
|
textureUtil = Fawe.get().getTextureUtil();
|
|
}
|
|
return this.textureUtil;
|
|
}
|
|
|
|
public TextureUtil getTextureUtil() {
|
|
if (textureUtil == null) {
|
|
textureUtil = Fawe.get().getTextureUtil();
|
|
}
|
|
try {
|
|
if (primitives.randomVariation) {
|
|
return new RandomTextureUtil(textureUtil);
|
|
} else if (textureUtil instanceof CachedTextureUtil) {
|
|
return textureUtil;
|
|
} else {
|
|
return new CachedTextureUtil(textureUtil);
|
|
}
|
|
} catch (FileNotFoundException neverHappens) {
|
|
neverHappens.printStackTrace();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void setBedrockId(int bedrockId) {
|
|
this.primitives.bedrockId = bedrockId;
|
|
}
|
|
|
|
public void setFloorThickness(int floorThickness) {
|
|
this.primitives.floorThickness = floorThickness;
|
|
}
|
|
|
|
public void setWorldThickness(int height) {
|
|
this.primitives.worldThickness = height;
|
|
}
|
|
|
|
public void setWaterHeight(int waterHeight) {
|
|
this.primitives.waterHeight = waterHeight;
|
|
}
|
|
|
|
public void setWaterId(int waterId) {
|
|
this.primitives.waterId = waterId;
|
|
}
|
|
|
|
public void setTextureRandomVariation(boolean randomVariation) {
|
|
this.primitives.randomVariation = randomVariation;
|
|
}
|
|
|
|
public boolean getTextureRandomVariation() {
|
|
return this.primitives.randomVariation;
|
|
}
|
|
|
|
public void setTextureUtil(TextureUtil textureUtil) {
|
|
this.textureUtil = textureUtil;
|
|
}
|
|
|
|
public void smooth(BufferedImage img, boolean white, int radius, int iterations) {
|
|
smooth(img, null, white, radius, iterations);
|
|
}
|
|
|
|
public void smooth(Mask mask, int radius, int iterations) {
|
|
smooth(null, mask, false, radius, iterations);
|
|
}
|
|
|
|
public void smooth(BlockVector2 min, BlockVector2 max, int radius, int iterations) {
|
|
int snowLayer = BlockTypes.SNOW.getInternalId();
|
|
int snowBlock = BlockTypes.SNOW_BLOCK.getInternalId();
|
|
|
|
int[] floor = this.floor.get();
|
|
byte[] heights = this.heights.get();
|
|
|
|
int width = getWidth();
|
|
int length = getLength();
|
|
|
|
int minX = min.getBlockX();
|
|
int minZ = min.getBlockZ();
|
|
|
|
int maxX = max.getBlockX();
|
|
int maxZ = max.getBlockZ();
|
|
|
|
int tableWidth = (maxX - minX + 1);
|
|
int tableLength = (maxZ - minZ + 1);
|
|
int smoothArea = tableWidth * tableLength;
|
|
|
|
long[] copy = new long[smoothArea];
|
|
char[] layers = new char[smoothArea];
|
|
|
|
SummedAreaTable table = new SummedAreaTable(copy, layers, tableWidth, radius);
|
|
for (int j = 0; j < iterations; j++) {
|
|
|
|
{ // Copy to table
|
|
int localIndex = 0;
|
|
int zIndex = (minZ * getWidth());
|
|
for (int z = minZ; z <= maxZ; z++, zIndex += getWidth()) {
|
|
int index = zIndex + minX;
|
|
for (int x = minX; x <= maxX; x++, index++, localIndex++) {
|
|
int combined = floor[index];
|
|
if (BlockTypes.getFromStateId(combined) == BlockTypes.SNOW) {
|
|
layers[localIndex] = (char) (((heights[index] & 0xFF) << 3) + (floor[index] >> BlockTypes.BIT_OFFSET) - 7);
|
|
} else {
|
|
layers[localIndex] = (char) (((heights[index] & 0xFF) << 3));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Process table
|
|
table.processSummedAreaTable();
|
|
// Copy from table
|
|
int localIndex = 0;
|
|
int zIndex = (minZ * getWidth());
|
|
for (int z = minZ, localZ = 0; z <= maxZ; z++, localZ++, zIndex += getWidth()) {
|
|
int index = zIndex + minX;
|
|
for (int x = minX, localX = 0; x <= maxX; x++, localX++, index++, localIndex++) {
|
|
int y = heights[index] & 0xFF;
|
|
int newHeight = table.average(localX, localZ, localIndex);
|
|
setLayerHeight(index, newHeight);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private final void setLayerHeight(int index, int height) {
|
|
int blockHeight = (height) >> 3;
|
|
int layerHeight = (height) & 0x7;
|
|
setLayerHeight(index, blockHeight, layerHeight);
|
|
}
|
|
|
|
private final void setLayerHeight(int index, int blockHeight, int layerHeight) {
|
|
int floorState = floor.get()[index];
|
|
BlockType type = BlockTypes.getFromStateId(floorState);
|
|
switch (type.getInternalId()) {
|
|
case BlockID.SNOW:
|
|
case BlockID.SNOW_BLOCK:
|
|
if (layerHeight != 0) {
|
|
this.heights.setByte(index, (byte) (blockHeight + 1));
|
|
this.floor.setInt(index, (BlockTypes.SNOW.getInternalId() + layerHeight));
|
|
} else {
|
|
this.heights.setByte(index, (byte) (blockHeight));
|
|
this.floor.setInt(index, (BlockTypes.SNOW_BLOCK.getInternalId()));
|
|
}
|
|
break;
|
|
default:
|
|
this.heights.setByte(index, (byte) (blockHeight));
|
|
break;
|
|
}
|
|
}
|
|
|
|
private final void setLayerHeightRaw(int index, int height) {
|
|
int blockHeight = (height) >> 3;
|
|
int layerHeight = (height) & 0x7;
|
|
setLayerHeightRaw(index, blockHeight, layerHeight);
|
|
}
|
|
|
|
private final void setLayerHeightRaw(int index, int blockHeight, int layerHeight) {
|
|
int floorState = floor.get()[index];
|
|
BlockType type = BlockTypes.getFromStateId(floorState);
|
|
switch (type.getInternalId()) {
|
|
case BlockID.SNOW:
|
|
case BlockID.SNOW_BLOCK:
|
|
if (layerHeight != 0) {
|
|
this.heights.getByteArray()[index] = (byte) (blockHeight + 1);
|
|
this.floor.getIntArray()[index] = (BlockTypes.SNOW.getInternalId() + layerHeight);
|
|
} else {
|
|
this.heights.getByteArray()[index] = (byte) (blockHeight);
|
|
this.floor.getIntArray()[index] = (BlockTypes.SNOW_BLOCK.getInternalId());
|
|
}
|
|
break;
|
|
default:
|
|
this.heights.getByteArray()[index] = (byte) (blockHeight);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void smooth(BufferedImage img, Mask mask, boolean white, int radius, int iterations) {
|
|
int[] floor = this.floor.get();
|
|
byte[] heights = this.heights.get();
|
|
|
|
long[] copy = new long[heights.length];
|
|
char[] layers = new char[heights.length];
|
|
|
|
this.floor.record(() -> HeightMapMCAGenerator.this.heights.record(() -> {
|
|
int width = getWidth();
|
|
int length = getLength();
|
|
SummedAreaTable table = new SummedAreaTable(copy, layers, width, radius);
|
|
for (int j = 0; j < iterations; j++) {
|
|
for (int i = 0; i < heights.length; i++) {
|
|
int combined = floor[i];
|
|
if (BlockTypes.getFromStateId(combined) == BlockTypes.SNOW) {
|
|
layers[i] = (char) (((heights[i] & 0xFF) << 3) + (floor[i] >> BlockTypes.BIT_OFFSET) - 7);
|
|
} else {
|
|
layers[i] = (char) (((heights[i] & 0xFF) << 3));
|
|
}
|
|
}
|
|
int index = 0;
|
|
table.processSummedAreaTable();
|
|
if (img != null) {
|
|
for (int z = 0; z < getLength(); z++) {
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int height = img.getRGB(x, z) & 0xFF;
|
|
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
|
|
.nextInt(256) <= height) {
|
|
int newHeight = table.average(x, z, index);
|
|
setLayerHeightRaw(index, newHeight);
|
|
}
|
|
}
|
|
}
|
|
} else if (mask != null) {
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights[index] & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (mask.test(mutable)) {
|
|
int newHeight = table.average(x, z, index);
|
|
setLayerHeightRaw(index, newHeight);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (int z = 0; z < getLength(); z++) {
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int newHeight = table.average(x, z, index);
|
|
setLayerHeightRaw(index, newHeight);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
public void setHeight(BufferedImage img) {
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
heights.setByte(index, (byte) (img.getRGB(x, z) >> 8));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void addCaves() throws WorldEditException {
|
|
CuboidRegion region = new CuboidRegion(BlockVector3.at(0, 0, 0), BlockVector3.at(getWidth() -1, 255, getLength() -1));
|
|
addCaves(region);
|
|
}
|
|
|
|
@Deprecated
|
|
public void addSchems(Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws WorldEditException {
|
|
CuboidRegion region = new CuboidRegion(BlockVector3.at(0, 0, 0), BlockVector3.at(getWidth() -1, 255, getLength() -1));
|
|
addSchems(region, mask, clipboards, rarity, rotate);
|
|
}
|
|
|
|
public void addSchems(BufferedImage img, Mask mask, List<ClipboardHolder> clipboards, int rarity, int distance, boolean randomRotate) throws WorldEditException {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
double doubleRarity = rarity / 100d;
|
|
int index = 0;
|
|
AffineTransform identity = new AffineTransform();
|
|
LocalBlockVector2DSet placed = new LocalBlockVector2DSet();
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
int height = img.getRGB(x, z) & 0xFF;
|
|
if (height == 0 || ThreadLocalRandom.current().nextInt(256) > height * doubleRarity) {
|
|
continue;
|
|
}
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (!mask.test(mutable)) {
|
|
continue;
|
|
}
|
|
if (placed.containsRadius(x, z, distance)) {
|
|
continue;
|
|
}
|
|
placed.add(x, z);
|
|
ClipboardHolder holder = clipboards.get(ThreadLocalRandom.current().nextInt(clipboards.size()));
|
|
if (randomRotate) {
|
|
int rotate = ThreadLocalRandom.current().nextInt(4) * 90;
|
|
if (rotate != 0) {
|
|
holder.setTransform(new AffineTransform().rotateY(ThreadLocalRandom.current().nextInt(4) * 90));
|
|
} else {
|
|
holder.setTransform(identity);
|
|
}
|
|
}
|
|
Clipboard clipboard = holder.getClipboard();
|
|
Schematic schematic = new Schematic(clipboard);
|
|
Transform transform = holder.getTransform();
|
|
if (transform.isIdentity()) {
|
|
schematic.paste(this, mutable, false);
|
|
} else {
|
|
schematic.paste(this, mutable, false, transform);
|
|
}
|
|
if (x + distance < getWidth()) {
|
|
x += distance;
|
|
index += distance;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void addSchems(Mask mask, List<ClipboardHolder> clipboards, int rarity, int distance, boolean randomRotate) throws WorldEditException {
|
|
int scaledRarity = (256 * rarity) / 100;
|
|
int index = 0;
|
|
AffineTransform identity = new AffineTransform();
|
|
LocalBlockVector2DSet placed = new LocalBlockVector2DSet();
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
if (ThreadLocalRandom.current().nextInt(256) > scaledRarity) {
|
|
continue;
|
|
}
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (!mask.test(mutable)) {
|
|
continue;
|
|
}
|
|
if (placed.containsRadius(x, z, distance)) {
|
|
continue;
|
|
}
|
|
mutable.mutY(y + 1);
|
|
placed.add(x, z);
|
|
ClipboardHolder holder = clipboards.get(ThreadLocalRandom.current().nextInt(clipboards.size()));
|
|
if (randomRotate) {
|
|
int rotate = ThreadLocalRandom.current().nextInt(4) * 90;
|
|
if (rotate != 0) {
|
|
holder.setTransform(new AffineTransform().rotateY(ThreadLocalRandom.current().nextInt(4) * 90));
|
|
} else {
|
|
holder.setTransform(identity);
|
|
}
|
|
}
|
|
Clipboard clipboard = holder.getClipboard();
|
|
Schematic schematic = new Schematic(clipboard);
|
|
Transform transform = holder.getTransform();
|
|
if (transform.isIdentity()) {
|
|
schematic.paste(this, mutable, false);
|
|
} else {
|
|
schematic.paste(this, mutable, false, transform);
|
|
}
|
|
if (x + distance < getWidth()) {
|
|
x += distance;
|
|
index += distance;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void addOre(Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
|
|
CuboidRegion region = new CuboidRegion(BlockVector3.at(0, 0, 0), BlockVector3.at(getWidth() -1, 255, getLength() -1));
|
|
addOre(region, mask, material, size, frequency, rarity, minY, maxY);
|
|
}
|
|
|
|
public void addDefaultOres(Mask mask) throws WorldEditException {
|
|
addOres(new CuboidRegion(BlockVector3.at(0, 0, 0), BlockVector3.at(getWidth() -1, 255, getLength() -1)), mask);
|
|
}
|
|
|
|
@Override
|
|
public BlockVector3 getMinimumPoint() {
|
|
return BlockVector3.at(0, 0, 0);
|
|
}
|
|
|
|
@Override
|
|
public FawePlayer getPlayer() {
|
|
return player;
|
|
}
|
|
|
|
@Override
|
|
public BlockVector3 getMaximumPoint() {
|
|
return BlockVector3.at(getWidth() - 1, 255, getLength() - 1);
|
|
}
|
|
|
|
@Override
|
|
public boolean setBlock(BlockVector3 position, BlockStateHolder block) throws WorldEditException {
|
|
return setBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ(), block);
|
|
}
|
|
|
|
private boolean setBlock(int x, int y, int z, int combined) {
|
|
int index = z * getWidth() + x;
|
|
if (index < 0 || index >= getArea()) return false;
|
|
int height = heights.getByte(index) & 0xFF;
|
|
switch (y - height) {
|
|
case 0:
|
|
floor.setInt(index, combined);
|
|
return true;
|
|
case 1:
|
|
int mainId = main.getInt(index);
|
|
int floorId = floor.getInt(index);
|
|
floor.setInt(index, combined);
|
|
|
|
byte currentHeight = heights.getByte(index);
|
|
currentHeight++;
|
|
heights.setByte(index, currentHeight);
|
|
if (mainId == floorId) return true;
|
|
y--;
|
|
combined = floorId;
|
|
default:
|
|
try {
|
|
blocks.set(x, y, z, combined);
|
|
return true;
|
|
} catch (IndexOutOfBoundsException ignore) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean setBiome(int x, int y, int z, BiomeType biome) {
|
|
int index = z * getWidth() + x;
|
|
if (index < 0 || index >= getArea()) return false;
|
|
biomes.setByte(index, (byte) biome.getInternalId());
|
|
return true;
|
|
}
|
|
|
|
// @Override TODO NOT IMPLEMENTED
|
|
// public FaweChunk getFaweChunk(int chunkX, int chunkZ) {
|
|
// return new SimpleIntFaweChunk(this, chunkX, chunkZ);
|
|
// }
|
|
//
|
|
// @Override
|
|
// public FaweChunk getSnapshot(int chunkX, int chunkZ) {
|
|
// return getSnapshot(null, chunkX, chunkZ);
|
|
// }
|
|
//
|
|
// private FaweChunk getSnapshot(final WritableMCAChunk chunk, int chunkX, int chunkZ) {
|
|
// return new LazyFaweChunk<WritableMCAChunk>(this, chunkX, chunkZ) {
|
|
// @Override
|
|
// public WritableMCAChunk getChunk() {
|
|
// WritableMCAChunk tmp = chunk;
|
|
// if (tmp == null) {
|
|
// tmp = new WritableMCAChunk();
|
|
// }
|
|
// tmp.setLoc(HeightMapMCAGenerator.this, chunkX, chunkZ);
|
|
// int cbx = chunkX << 4;
|
|
// int cbz = chunkZ << 4;
|
|
// int csx = Math.max(0, cbx);
|
|
// int csz = Math.max(0, cbz);
|
|
// int cex = Math.min(getWidth(), cbx + 15);
|
|
// int cez = Math.min(getLength(), cbz + 15);
|
|
// write(tmp, csx, cex, csz, cez);
|
|
// tmp.setLoc(HeightMapMCAGenerator.this, getX(), getZ());
|
|
// return tmp;
|
|
// }
|
|
//
|
|
// @Override
|
|
// public void addToQueue() {
|
|
// WritableMCAChunk cached = getCachedChunk();
|
|
// if (cached != null) setChunk(cached);
|
|
// }
|
|
// };
|
|
// }
|
|
//
|
|
// @Override
|
|
// public Collection<FaweChunk> getFaweChunks() {
|
|
// return Collections.emptyList();
|
|
// }
|
|
//
|
|
// @Override
|
|
// public void setChunk(FaweChunk chunk) {
|
|
// int[][] src = chunk.getCombinedIdArrays();
|
|
// for (int i = 0; i < src.length; i++) {
|
|
// if (src[i] != null) {
|
|
// int bx = chunk.getX() << 4;
|
|
// int bz = chunk.getZ() << 4;
|
|
// int by = i << 4;
|
|
// for (int layer = i; layer < src.length; layer++) {
|
|
// int[] srcLayer = src[layer];
|
|
// if (srcLayer != null) {
|
|
// int index = 0;
|
|
// for (int y = 0; y < 16; y++) {
|
|
// int yy = by + y;
|
|
// for (int z = 0; z < 16; z++) {
|
|
// int zz = bz + z;
|
|
// for (int x = 0; x < 16; x++, index++) {
|
|
// int combined = srcLayer[index];
|
|
// if (combined != 0) {
|
|
// setBlock(bx + x, yy, zz, combined);
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
@Nullable
|
|
@Override
|
|
public Path getStoragePath() {
|
|
return getFolder().toPath();
|
|
}
|
|
|
|
@Override
|
|
public boolean regenerateChunk(int x, int z, @Nullable BiomeType biome, @Nullable Long seed) {
|
|
// Unsupported
|
|
return false;
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public Operation commit() {
|
|
EditSession curES = editSession;
|
|
if (curES != null && isModified()) {
|
|
try {
|
|
update();
|
|
FawePlayer esPlayer = curES.getPlayer();
|
|
UUID uuid = esPlayer != null ? esPlayer.getUUID() : EditSession.CONSOLE;
|
|
try {
|
|
curES.setRawChangeSet(new CFIChangeSet(this, uuid));
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
} catch (Throwable e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void close(boolean update) {
|
|
if (chunkOffset != null && player != null && update) {
|
|
World world = player.getWorld();
|
|
|
|
int lenCX = (getWidth() + 15) >> 4;
|
|
int lenCZ = (getLength() + 15) >> 4;
|
|
|
|
int OX = chunkOffset.getBlockX();
|
|
int OZ = chunkOffset.getBlockZ();
|
|
|
|
Location position = player.getLocation();
|
|
int pcx = (position.getBlockX() >> 4) - OX;
|
|
int pcz = (position.getBlockZ() >> 4) - OZ;
|
|
|
|
int scx = Math.max(0, pcx - 10);
|
|
int scz = Math.max(0, pcz - 10);
|
|
int ecx = Math.min(lenCX - 1, pcx + 10);
|
|
int ecz = Math.min(lenCZ - 1, pcz + 10);
|
|
|
|
for (int cz = scz; cz <= ecz; cz++) {
|
|
for (int cx = scx; cx <= ecx; cx++) {
|
|
world.sendChunk(cx + OX, cz + OZ, 0);
|
|
}
|
|
}
|
|
}
|
|
if (player != null) {
|
|
player.deleteMeta("CFISettings");
|
|
LocalSession session = player.getSession();
|
|
session.clearHistory();
|
|
}
|
|
player = null;
|
|
chunkOffset = null;
|
|
}
|
|
|
|
@Override
|
|
public BiomeType getBiomeType(int x, int z) throws FaweException.FaweChunkLoadException {
|
|
int index = z * getWidth() + x;
|
|
if (index < 0 || index >= getArea()) index = Math.floorMod(index, getArea());
|
|
return BiomeTypes.get(biomes.getByte(index));
|
|
}
|
|
|
|
// @Override
|
|
public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
|
|
int index = z * getWidth() + x;
|
|
if (y < 0) return 0;
|
|
if (index < 0 || index >= getArea() || x < 0 || x >= getWidth()) return 0;
|
|
int height = heights.getByte(index) & 0xFF;
|
|
if (y > height) {
|
|
if (y == height + 1) {
|
|
return overlay != null ? overlay.getInt(index) : 0;
|
|
}
|
|
if (blocks != null) {
|
|
short chunkX = (short) (x >> 4);
|
|
short chunkZ = (short) (z >> 4);
|
|
int[][][] map = getChunkArray(chunkX, chunkZ);
|
|
if (map != null) {
|
|
int combined = get(map, x, y, z);
|
|
if (combined != 0) {
|
|
return combined;
|
|
}
|
|
}
|
|
}
|
|
if (y <= primitives.waterHeight) {
|
|
return primitives.waterId << 4;
|
|
}
|
|
return 0;
|
|
} else if (y == height) {
|
|
return floor.getInt(index);
|
|
} else {
|
|
if (blocks != null) {
|
|
short chunkX = (short) (x >> 4);
|
|
short chunkZ = (short) (z >> 4);
|
|
int[][][] map = getChunkArray(chunkX, chunkZ);
|
|
if (map != null) {
|
|
int combined = get(map, x, y, z);
|
|
if (combined != 0) {
|
|
return combined;
|
|
}
|
|
}
|
|
}
|
|
return main.getInt(index);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException {
|
|
return this.setBlock(x, y, z, block.getInternalId());
|
|
}
|
|
|
|
@Override
|
|
public BiomeType getBiome(BlockVector2 position) {
|
|
return getBiomeType(position.getBlockX(), position.getBlockZ());
|
|
}
|
|
|
|
@Override
|
|
public BlockState getBlock(BlockVector3 position) {
|
|
return getBlock(position.getX(), position.getY(), position.getZ());
|
|
}
|
|
|
|
public BlockState getFloor(int x, int z) {
|
|
int index = z * getWidth() + x;
|
|
return BlockState.getFromInternalId(floor.getInt(index));
|
|
}
|
|
|
|
public int getHeight(int x, int z) {
|
|
int index = z * getWidth() + x;
|
|
return heights.getByte(index) & 0xFF;
|
|
}
|
|
|
|
public int getHeight(int index) {
|
|
return heights.getByte(index) & 0xFF;
|
|
}
|
|
|
|
public void setFloor(int x, int z, BlockStateHolder block) {
|
|
int index = z * getWidth() + x;
|
|
floor.setInt(index, block.getInternalId());
|
|
}
|
|
|
|
@Override
|
|
public BlockState getBlock(int x, int y, int z) {
|
|
return BlockState.getFromInternalId(getCombinedId4Data(x, y, z));
|
|
}
|
|
|
|
@Override
|
|
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
|
int index = z * getWidth() + x;
|
|
if (index < 0 || index >= getArea()) index = Math.floorMod(index, getArea());
|
|
return ((heights.getByte(index) & 0xFF) << 3) + (floor.getInt(index) & 0xFF) + 1;
|
|
}
|
|
|
|
@Override
|
|
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
|
int index = z * getWidth() + x;
|
|
if (index < 0 || index >= getArea()) index = Math.floorMod(index, getArea());
|
|
return heights.getByte(index) & 0xFF;
|
|
}
|
|
|
|
@Override
|
|
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
|
|
int index = z * getWidth() + x;
|
|
if (index < 0 || index >= getArea()) index = Math.floorMod(index, getArea());
|
|
return heights.getByte(index) & 0xFF;
|
|
}
|
|
|
|
public void setBiome(BufferedImage img, BiomeType biome, boolean white) {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
byte biomeByte = (byte) biome.getInternalId();
|
|
biomes.record(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
byte[] biomeArr = biomes.get();
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int height = img.getRGB(x, z) & 0xFF;
|
|
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
|
|
.nextInt(256) <= height) {
|
|
biomeArr[index] = biomeByte;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public BufferedImage draw() {
|
|
// TODO NOT IMPLEMENTED
|
|
// return new HeightMapMCADrawer(this).draw();
|
|
return null;
|
|
}
|
|
|
|
public void setBiomePriority(int value) {
|
|
this.primitives.biomePriority = ((value * 65536) / 100) - 32768;
|
|
}
|
|
|
|
public int getBiomePriority() {
|
|
return ((primitives.biomePriority + 32768) * 100) / 65536;
|
|
}
|
|
|
|
public void setBlockAndBiomeColor(BufferedImage img, Mask mask, BufferedImage imgMask, boolean whiteOnly) {
|
|
if (mask == null && imgMask == null) {
|
|
setBlockAndBiomeColor(img);
|
|
return;
|
|
}
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
TextureUtil textureUtil = getTextureUtil();
|
|
|
|
int widthIndex = img.getWidth() - 1;
|
|
int heightIndex = img.getHeight() - 1;
|
|
int maxIndex = getArea() - 1;
|
|
|
|
biomes.record(() -> floor.record(() -> main.record(() -> {
|
|
int[] mainArr = main.get();
|
|
int[] floorArr = floor.get();
|
|
byte[] biomesArr = biomes.get();
|
|
|
|
int index = 0;
|
|
int[] buffer = new int[2];
|
|
for (int z = 0; z < img.getHeight(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < img.getWidth(); x++, index++) {
|
|
if (mask != null) {
|
|
mutable.mutX(z);
|
|
mutable.mutY(heights.getByte(index) & 0xFF);
|
|
if (!mask.test(mutable)) continue;
|
|
}
|
|
if (imgMask != null) {
|
|
int height = imgMask.getRGB(x, z) & 0xFF;
|
|
if (height != 255 && (height <= 0 || !whiteOnly || ThreadLocalRandom
|
|
.current().nextInt(256) > height)) continue;
|
|
}
|
|
int color = img.getRGB(x, z);
|
|
if (textureUtil.getIsBlockCloserThanBiome(buffer, color, primitives.biomePriority)) {
|
|
int combined = buffer[0];
|
|
mainArr[index] = combined;
|
|
floorArr[index] = combined;
|
|
}
|
|
biomesArr[index] = (byte) buffer[1];
|
|
}
|
|
}
|
|
})));
|
|
}
|
|
|
|
public void setBlockAndBiomeColor(BufferedImage img) {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
TextureUtil textureUtil = getTextureUtil();
|
|
int widthIndex = img.getWidth() - 1;
|
|
int heightIndex = img.getHeight() - 1;
|
|
int maxIndex = getArea() - 1;
|
|
|
|
biomes.record(() -> floor.record(() -> main.record(() -> {
|
|
int[] mainArr = main.get();
|
|
int[] floorArr = floor.get();
|
|
byte[] biomesArr = biomes.get();
|
|
|
|
int[] buffer = new int[2];
|
|
int index = 0;
|
|
for (int y = 0; y < img.getHeight(); y++) {
|
|
boolean yBiome = y > 0 && y < heightIndex;
|
|
for (int x = 0; x < img.getWidth(); x++, index++) {
|
|
int color = img.getRGB(x, y);
|
|
if (textureUtil.getIsBlockCloserThanBiome(buffer, color, primitives.biomePriority)) {
|
|
int combined = buffer[0];
|
|
mainArr[index] = combined;
|
|
floorArr[index] = combined;
|
|
}
|
|
biomesArr[index] = (byte) buffer[1];
|
|
}
|
|
}
|
|
})));
|
|
}
|
|
|
|
public void setBiomeColor(BufferedImage img) {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
TextureUtil textureUtil = getTextureUtil();
|
|
|
|
biomes.record(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
byte[] biomesArr = biomes.get();
|
|
int index = 0;
|
|
for (int y = 0; y < img.getHeight(); y++) {
|
|
for (int x = 0; x < img.getWidth(); x++) {
|
|
int color = img.getRGB(x, y);
|
|
TextureUtil.BiomeColor biome = textureUtil.getNearestBiome(color);
|
|
if (biome != null) {
|
|
biomesArr[index] = (byte) biome.id;
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public void setColor(BufferedImage img, BufferedImage mask, boolean white) {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
if (mask.getWidth() != getWidth() || mask.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
primitives.modifiedMain = true;
|
|
TextureUtil textureUtil = getTextureUtil();
|
|
|
|
floor.record(() -> main.record(() -> {
|
|
int[] mainArr = main.get();
|
|
int[] floorArr = floor.get();
|
|
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int height = mask.getRGB(x, z) & 0xFF;
|
|
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
|
|
.nextInt(256) <= height) {
|
|
int color = img.getRGB(x, z);
|
|
BlockType block = textureUtil.getNearestBlock(color);
|
|
if (block != null) {
|
|
int combined = block.getInternalId();
|
|
mainArr[index] = combined;
|
|
floorArr[index] = combined;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
public void setColor(BufferedImage img, Mask mask) {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
primitives.modifiedMain = true;
|
|
TextureUtil textureUtil = getTextureUtil();
|
|
|
|
|
|
floor.record(() -> main.record(() -> {
|
|
int[] mainArr = main.get();
|
|
int[] floorArr = floor.get();
|
|
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
mutable.mutX(x);
|
|
mutable.mutY(heights.getByte(index) & 0xFF);
|
|
if (mask.test(mutable)) {
|
|
int color = img.getRGB(x, z);
|
|
BlockType block = textureUtil.getNearestBlock(color);
|
|
if (block != null) {
|
|
int combined = block.getInternalId();
|
|
mainArr[index] = combined;
|
|
floorArr[index] = combined;
|
|
} else {
|
|
System.out.println("Block is null: " + color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
public void setColor(BufferedImage img) {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
primitives.modifiedMain = true;
|
|
TextureUtil textureUtil = getTextureUtil();
|
|
|
|
floor.record(() -> main.record(() -> {
|
|
int[] mainArr = main.get();
|
|
int[] floorArr = floor.get();
|
|
|
|
int index = 0;
|
|
for (int z = 0; z < img.getHeight(); z++) {
|
|
for (int x = 0; x < img.getWidth(); x++) {
|
|
int color = img.getRGB(x, z);
|
|
BlockType block = textureUtil.getNearestBlock(color);
|
|
if (block != null) {
|
|
int combined = block.getInternalId();
|
|
mainArr[index] = combined;
|
|
floorArr[index] = combined;
|
|
} else {
|
|
System.out.println("Block is null " + color + " | " + textureUtil.getClass());
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
public void setColorWithGlass(BufferedImage img) {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
TextureUtil textureUtil = getTextureUtil();
|
|
|
|
floor.record(() -> main.record(() -> {
|
|
int[] mainArr = main.get();
|
|
int[] floorArr = floor.get();
|
|
|
|
int index = 0;
|
|
for (int y = 0; y < img.getHeight(); y++) {
|
|
for (int x = 0; x < img.getWidth(); x++) {
|
|
int color = img.getRGB(x, y);
|
|
BlockType[] layer = textureUtil.getNearestLayer(color);
|
|
if (layer != null) {
|
|
floorArr[index] = layer[0].getInternalId();
|
|
mainArr[index] = layer[1].getInternalId();
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
public void setBiome(Mask mask, BiomeType biome) {
|
|
int index = 0;
|
|
byte biomeByte = (byte) biome.getInternalId();
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (mask.test(mutable)) {
|
|
biomes.setByte(index, biomeByte);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setOverlay(BufferedImage img, Pattern pattern, boolean white) {
|
|
if (pattern instanceof BlockStateHolder) {
|
|
setOverlay(img, ((BlockStateHolder) pattern).getInternalId(), white);
|
|
} else if (pattern instanceof BlockType) {
|
|
setOverlay(img, ((BlockType) pattern).getInternalId(), white);
|
|
} else {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
if (overlay == null) {
|
|
overlay = new DifferentialArray<>(new int[getArea()]);
|
|
}
|
|
|
|
overlay.record(() -> {
|
|
int[] overlayArr = overlay.get();
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int height = img.getRGB(x, z) & 0xFF;
|
|
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
|
|
.nextInt(256) <= height) {
|
|
mutable.mutX(x);
|
|
mutable.mutY(height);
|
|
overlayArr[index] = pattern.apply(mutable).getInternalId();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
}
|
|
}
|
|
|
|
public void setMain(BufferedImage img, Pattern pattern, boolean white) {
|
|
if (pattern instanceof BlockStateHolder) {
|
|
setMain(img, ((BlockStateHolder) pattern).getInternalId(), white);
|
|
} else {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
primitives.modifiedMain = true;
|
|
|
|
main.record(() -> {
|
|
int[] mainArr = main.get();
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int height = img.getRGB(x, z) & 0xFF;
|
|
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
|
|
.nextInt(256) <= height) {
|
|
mutable.mutX(x);
|
|
mutable.mutY(height);
|
|
mainArr[index] = pattern.apply(mutable).getInternalId();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public void setFloor(BufferedImage img, Pattern pattern, boolean white) {
|
|
if (pattern instanceof BlockStateHolder) {
|
|
setFloor(img, ((BlockStateHolder) pattern).getInternalId(), white);
|
|
} else {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
|
|
floor.record(() -> {
|
|
int[] floorArr = floor.get();
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int height = img.getRGB(x, z) & 0xFF;
|
|
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
|
|
.nextInt(256) <= height) {
|
|
mutable.mutX(x);
|
|
mutable.mutY(height);
|
|
floorArr[index] = pattern.apply(mutable).getInternalId();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public void setColumn(BufferedImage img, Pattern pattern, boolean white) {
|
|
if (pattern instanceof BlockStateHolder) {
|
|
setColumn(img, ((BlockStateHolder) pattern).getInternalId(), white);
|
|
} else {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
primitives.modifiedMain = true;
|
|
|
|
main.record(() -> floor.record(() -> {
|
|
int[] floorArr = floor.get();
|
|
int[] mainArr = main.get();
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int height = img.getRGB(x, z) & 0xFF;
|
|
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
|
|
.nextInt(256) <= height) {
|
|
mutable.mutX(x);
|
|
mutable.mutY(height);
|
|
int combined = pattern.apply(mutable).getInternalId();
|
|
mainArr[index] = combined;
|
|
floorArr[index] = combined;
|
|
}
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
|
|
public void setOverlay(Mask mask, Pattern pattern) {
|
|
if (pattern instanceof BlockStateHolder) {
|
|
setOverlay(mask, ((BlockStateHolder) pattern).getInternalId());
|
|
} else {
|
|
int index = 0;
|
|
if (overlay == null) overlay = new DifferentialArray<>(new int[getArea()]);
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (mask.test(mutable)) {
|
|
overlay.setInt(index, pattern.apply(mutable).getInternalId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setFloor(Mask mask, Pattern pattern) {
|
|
if (pattern instanceof BlockStateHolder) {
|
|
setFloor(mask, ((BlockStateHolder) pattern).getInternalId());
|
|
} else {
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (mask.test(mutable)) {
|
|
floor.setInt(index, pattern.apply(mutable).getInternalId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setMain(Mask mask, Pattern pattern) {
|
|
if (pattern instanceof BlockStateHolder) {
|
|
setMain(mask, ((BlockStateHolder) pattern).getInternalId());
|
|
} else {
|
|
primitives.modifiedMain = true;
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (mask.test(mutable)) {
|
|
main.setInt(index, pattern.apply(mutable).getInternalId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setColumn(Mask mask, Pattern pattern) {
|
|
if (pattern instanceof BlockStateHolder) {
|
|
setColumn(mask, ((BlockStateHolder) pattern).getInternalId());
|
|
} else {
|
|
primitives.modifiedMain = true;
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (mask.test(mutable)) {
|
|
int combined = pattern.apply(mutable).getInternalId();
|
|
floor.setInt(index, combined);
|
|
main.setInt(index, combined);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setBiome(BiomeType biome) {
|
|
biomes.record(() -> Arrays.fill(biomes.get(), (byte) biome.getInternalId()));
|
|
}
|
|
|
|
public void setFloor(Pattern value) {
|
|
if (value instanceof BlockStateHolder) {
|
|
setFloor(((BlockStateHolder) value).getInternalId());
|
|
} else {
|
|
floor.record(() -> {
|
|
int[] floorArr = floor.get();
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
floorArr[index] = value.apply(mutable).getInternalId();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public void setColumn(Pattern value) {
|
|
if (value instanceof BlockStateHolder) {
|
|
setColumn(((BlockStateHolder) value).getInternalId());
|
|
} else {
|
|
main.record(() -> floor.record(() -> {
|
|
int[] floorArr = floor.get();
|
|
int[] mainArr = main.get();
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
int combined = value.apply(mutable).getInternalId();
|
|
mainArr[index] = combined;
|
|
floorArr[index] = combined;
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
|
|
public void setMain(Pattern value) {
|
|
if (value instanceof BlockStateHolder) {
|
|
setMain(((BlockStateHolder) value).getInternalId());
|
|
} else {
|
|
main.record(() -> {
|
|
int[] mainArr = main.get();
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
mainArr[index] = value.apply(mutable).getInternalId();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public void setOverlay(Pattern value) {
|
|
if (overlay == null) overlay = new DifferentialArray<>(new int[getArea()]);
|
|
if (value instanceof BlockStateHolder) {
|
|
setOverlay(((BlockStateHolder) value).getInternalId());
|
|
} else {
|
|
overlay.record(() -> {
|
|
int[] overlayArr = overlay.get();
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
overlayArr[index] = value.apply(mutable).getInternalId();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public void setHeight(int x, int z, int height) {
|
|
int index = z * getWidth() + x;
|
|
if (index < 0 || index >= getArea()) return;
|
|
heights.setByte(index, (byte) height);
|
|
}
|
|
|
|
public void setHeight(int index, int height) {
|
|
heights.setByte(index, (byte) height);
|
|
}
|
|
|
|
public void setHeights(int value) {
|
|
heights.record(() -> {
|
|
Arrays.fill(heights.get(), (byte) value);
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldWrite(int chunkX, int chunkZ) {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public WritableMCAChunk write(WritableMCAChunk chunk, int csx, int cex, int csz, int cez) {
|
|
byte[] heights = this.heights.get();
|
|
byte[] biomes = this.biomes.get();
|
|
int[] main = this.main.get();
|
|
int[] floor = this.floor.get();
|
|
int[] overlay = this.overlay != null ? this.overlay.get() : null;
|
|
try {
|
|
int[] indexes = FaweCache.IMP.INDEX_STORE.get();
|
|
|
|
int index;
|
|
int maxY = 0;
|
|
int minY = Integer.MAX_VALUE;
|
|
int[] heightMap = chunk.biomes;
|
|
int globalIndex;
|
|
for (int z = csz; z <= cez; z++) {
|
|
globalIndex = z * getWidth() + csx;
|
|
index = (z & 15) << 4;
|
|
for (int x = csx; x <= cex; x++, index++, globalIndex++) {
|
|
indexes[index] = globalIndex;
|
|
int height = heights[globalIndex] & 0xFF;
|
|
heightMap[index] = height;
|
|
maxY = Math.max(maxY, height);
|
|
minY = Math.min(minY, height);
|
|
}
|
|
}
|
|
boolean hasOverlay = this.overlay != null;
|
|
if (hasOverlay) {
|
|
maxY++;
|
|
}
|
|
int maxLayer = maxY >> 4;
|
|
for (int layer = 0; layer <= maxLayer; layer++) {
|
|
chunk.hasSections[layer] = true;
|
|
}
|
|
if (primitives.waterHeight != 0) {
|
|
int maxIndex = (primitives.waterHeight) << 8;
|
|
Arrays.fill(chunk.blocks, 0, maxIndex, primitives.waterId);
|
|
}
|
|
|
|
if (primitives.modifiedMain) { // If the main block is modified, we can't short circuit this
|
|
for (int z = csz; z <= cez; z++) {
|
|
index = (z & 15) << 4;
|
|
for (int x = csx; x <= cex; x++, index++) {
|
|
globalIndex = indexes[index];
|
|
int mainCombined = main[globalIndex];
|
|
for (int y = 0; y < minY; y++) {
|
|
chunk.blocks[index + (y << 8)] = mainCombined;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
int maxIndex = minY << 8;
|
|
Arrays.fill(chunk.blocks, 0, maxIndex, BlockID.STONE);
|
|
}
|
|
|
|
final boolean hasFloorThickness = primitives.floorThickness != 0 || primitives.worldThickness != 0;
|
|
if (primitives.worldThickness != 0) {
|
|
int endLayer = ((minY - primitives.worldThickness + 1) >> 4);
|
|
for (int layer = 0; layer < endLayer; layer++) {
|
|
chunk.hasSections[layer] = false;
|
|
}
|
|
}
|
|
|
|
for (int z = csz; z <= cez; z++) {
|
|
index = (z & 15) << 4;
|
|
for (int x = csx; x <= cex; x++, index++) {
|
|
globalIndex = indexes[index];
|
|
int height = heightMap[index];
|
|
int maxMainY = height;
|
|
int minMainY = minY;
|
|
|
|
int mainCombined = main[globalIndex];
|
|
|
|
int floorCombined = floor[globalIndex];
|
|
if (hasFloorThickness) {
|
|
if (x > 0) maxMainY = Math.min(heights[globalIndex - 1] & 0xFF, maxMainY);
|
|
if (x < getWidth() - 1) maxMainY = Math.min(heights[globalIndex + 1] & 0xFF, maxMainY);
|
|
if (z > 0) maxMainY = Math.min(heights[globalIndex - getWidth()] & 0xFF, maxMainY);
|
|
if (z < getLength() - 1) maxMainY = Math.min(heights[globalIndex + getWidth()] & 0xFF, maxMainY);
|
|
|
|
int min = maxMainY;
|
|
|
|
if (primitives.floorThickness != 0) {
|
|
maxMainY = Math.max(0, maxMainY - (primitives.floorThickness - 1));
|
|
for (int y = maxMainY; y <= height; y++) {
|
|
chunk.blocks[index + (y << 8)] = floorCombined;
|
|
}
|
|
}
|
|
else {
|
|
chunk.blocks[index + ((height) << 8)] = floorCombined;
|
|
}
|
|
|
|
if (primitives.worldThickness != 0) {
|
|
minMainY = Math.max(minY, min - primitives.worldThickness + 1);
|
|
for (int y = minY; y < minMainY; y++) {
|
|
chunk.blocks[index + (y << 8)] = BlockID.AIR;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
chunk.blocks[index + ((height) << 8)] = floorCombined;
|
|
}
|
|
|
|
for (int y = minMainY; y < maxMainY; y++) {
|
|
chunk.blocks[index + (y << 8)] = mainCombined;
|
|
}
|
|
|
|
if (hasOverlay) {
|
|
int overlayCombined = overlay[globalIndex];
|
|
int overlayIndex = index + ((height + 1) << 8);
|
|
chunk.blocks[overlayIndex] = overlayCombined;
|
|
}
|
|
|
|
if (primitives.bedrockId != 0) {
|
|
chunk.blocks[index] = primitives.bedrockId;
|
|
}
|
|
}
|
|
}
|
|
|
|
int[][][] localBlocks = getChunkArray(chunk.getX(), chunk.getZ());
|
|
if (localBlocks != null) {
|
|
index = 0;
|
|
for (int layer = 0; layer < 16; layer++) {
|
|
int by = layer << 4;
|
|
int ty = by + 15;
|
|
for (int y = by; y <= ty; y++, index += 256) {
|
|
int[][] yBlocks = localBlocks[y];
|
|
if (yBlocks != null) {
|
|
chunk.hasSections[layer] = true;
|
|
for (int z = 0; z < yBlocks.length; z++) {
|
|
int[] zBlocks = yBlocks[z];
|
|
if (zBlocks != null) {
|
|
int zIndex = index + (z << 4);
|
|
for (int x = 0; x < zBlocks.length; x++, zIndex++) {
|
|
int combined = zBlocks[x];
|
|
if (combined == 0) continue;
|
|
chunk.blocks[zIndex] = combined;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 256; i++) {
|
|
chunk.biomes[i] = biomes[indexes[i]];
|
|
}
|
|
|
|
|
|
} catch (Throwable e) {
|
|
e.printStackTrace();
|
|
}
|
|
return chunk;
|
|
}
|
|
|
|
private void setUnsafe(int[][][] map, int combined, int x, int y, int z) {
|
|
int[][] yMap = map[y];
|
|
if (yMap == null) {
|
|
map[y] = yMap = new int[16][];
|
|
}
|
|
int[] zMap = yMap[z];
|
|
if (zMap == null) {
|
|
yMap[z] = zMap = new int[16];
|
|
}
|
|
zMap[x] = combined;
|
|
}
|
|
|
|
private int get(int[][][] map, int x, int y, int z) {
|
|
int[][] yMap = map[y];
|
|
if (yMap == null) {
|
|
return 0;
|
|
}
|
|
int[] zMap = yMap[z & 15];
|
|
if (zMap == null) {
|
|
return 0;
|
|
}
|
|
return zMap[x & 15];
|
|
}
|
|
|
|
private void setOverlay(Mask mask, int combined) {
|
|
int index = 0;
|
|
if (overlay == null) overlay = new DifferentialArray<>(new int[getArea()]);
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (mask.test(mutable)) {
|
|
overlay.setInt(index, combined);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void setFloor(Mask mask, int combined) {
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (mask.test(mutable)) {
|
|
floor.setInt(index, combined);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void setMain(Mask mask, int combined) {
|
|
primitives.modifiedMain = true;
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (mask.test(mutable)) {
|
|
main.setInt(index, combined);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void setColumn(Mask mask, int combined) {
|
|
primitives.modifiedMain = true;
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
mutable.mutZ(z);
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int y = heights.getByte(index) & 0xFF;
|
|
mutable.mutX(x);
|
|
mutable.mutY(y);
|
|
if (mask.test(mutable)) {
|
|
floor.setInt(index, combined);
|
|
main.setInt(index, combined);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void setFloor(int value) {
|
|
floor.record(() -> Arrays.fill(floor.get(), value));
|
|
}
|
|
|
|
private void setColumn(int value) {
|
|
setFloor(value);
|
|
setMain(value);
|
|
}
|
|
|
|
private void setMain(int value) {
|
|
primitives.modifiedMain = true;
|
|
main.record(() -> Arrays.fill(main.get(), value));
|
|
}
|
|
|
|
private void setOverlay(int value) {
|
|
if (overlay == null) overlay = new DifferentialArray<>(new int[getArea()]);
|
|
overlay.record(() -> Arrays.fill(overlay.get(), value));
|
|
}
|
|
|
|
private void setOverlay(BufferedImage img, int combined, boolean white) {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
if (overlay == null) overlay = new DifferentialArray<>(new int[getArea()]);
|
|
|
|
overlay.record(() -> {
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int height = img.getRGB(x, z) & 0xFF;
|
|
if (height == 255 || height > 0 && white && ThreadLocalRandom.current()
|
|
.nextInt(256) <= height) {
|
|
overlay.get()[index] = combined;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private void setMain(BufferedImage img, int combined, boolean white) {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
primitives.modifiedMain = true;
|
|
|
|
main.record(() -> {
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int height = img.getRGB(x, z) & 0xFF;
|
|
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
|
|
.nextInt(256) <= height) {
|
|
main.get()[index] = combined;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private void setFloor(BufferedImage img, int combined, boolean white) {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
|
|
floor.record(() -> {
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int height = img.getRGB(x, z) & 0xFF;
|
|
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
|
|
.nextInt(256) <= height) {
|
|
floor.get()[index] = combined;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private void setColumn(BufferedImage img, int combined, boolean white) {
|
|
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
|
|
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
|
primitives.modifiedMain = true;
|
|
|
|
main.record(() -> floor.record(() -> {
|
|
int index = 0;
|
|
for (int z = 0; z < getLength(); z++) {
|
|
for (int x = 0; x < getWidth(); x++, index++) {
|
|
int height = img.getRGB(x, z) & 0xFF;
|
|
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
|
|
.nextInt(256) <= height) {
|
|
main.get()[index] = combined;
|
|
floor.get()[index] = combined;
|
|
}
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
@Override
|
|
public int getMaxY() {
|
|
return 255;
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
File folder = getFolder();
|
|
if (folder != null) {
|
|
String name = folder.getName();
|
|
if (name.equalsIgnoreCase("region")) return folder.getParentFile().getName();
|
|
return name;
|
|
}
|
|
return Integer.toString(hashCode());
|
|
}
|
|
|
|
@Override
|
|
public boolean setBlock(BlockVector3 position, BlockStateHolder block, boolean notifyAndLight) throws WorldEditException {
|
|
return setBlock(position, block);
|
|
}
|
|
|
|
// These aren't implemented yet...
|
|
@Override
|
|
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int getBlockLightLevel(BlockVector3 position) {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public boolean clearContainerBlockContents(BlockVector3 position) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean regenerate(Region region, EditSession editSession) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void dropItem(Vector3 position, BaseItemStack item) {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
@Override
|
|
public boolean playEffect(Vector3 position, int type, int data) {
|
|
// TODO Auto-generated method stub
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
|
|
// TODO Auto-generated method stub
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public BlockVector3 getSpawnPosition() {
|
|
// TODO Auto-generated method stub
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public IChunkGet get(int x, int z) {
|
|
Fawe.debug("Should not be using buffering with HMMG");
|
|
return new FallbackChunkGet(this, x, z);
|
|
}
|
|
}
|