mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-22 17:27:38 +00:00
Implement a "sensitivity" setting, a mask, and an option to only distinguish air vs blocks to blendball (#1832)
This commit is contained in:
parent
d498996cbd
commit
100288ada5
@ -1,5 +1,7 @@
|
||||
package com.fastasyncworldedit.core.command.tool.brush;
|
||||
|
||||
import com.fastasyncworldedit.core.function.mask.CachedMask;
|
||||
import com.fastasyncworldedit.core.math.MutableBlockVector3;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.command.tool.brush.Brush;
|
||||
@ -8,10 +10,40 @@ import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class BlendBall implements Brush {
|
||||
|
||||
private static final BlockState AIR = BlockTypes.AIR.getDefaultState();
|
||||
|
||||
private final int minFreqDiff;
|
||||
private final boolean onlyAir;
|
||||
@Nullable private final CachedMask mask;
|
||||
|
||||
/**
|
||||
* Create a new {@link Brush} instance with default settings.
|
||||
*/
|
||||
public BlendBall() {
|
||||
this(1, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Brush} instance.
|
||||
*
|
||||
* @param minFreqDiff Minimum difference between nearby blocks (3x3x3 cuboid centered on position) to alter the current block
|
||||
* at a position
|
||||
* @param onlyAir Only consider air for comparing existing blocks, and for altering existing blocks
|
||||
* @param mask Mask to limit the blocks being considered for alteration. Will also limit blocks types able to be
|
||||
* placed, and will consider blocks not meeting the mask as air
|
||||
* @since TODO
|
||||
*/
|
||||
public BlendBall(int minFreqDiff, boolean onlyAir, @Nullable CachedMask mask) {
|
||||
this.minFreqDiff = minFreqDiff;
|
||||
this.onlyAir = onlyAir;
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws
|
||||
MaxChangedBlocksException {
|
||||
@ -27,41 +59,75 @@ public class BlendBall implements Brush {
|
||||
int maxY = editSession.getMaxY();
|
||||
int minY = editSession.getMinY();
|
||||
|
||||
MutableBlockVector3 mutable = new MutableBlockVector3();
|
||||
for (int x = -outsetSize; x <= outsetSize; x++) {
|
||||
int x0 = x + tx;
|
||||
int xx = x * x;
|
||||
for (int y = -outsetSize; y <= outsetSize; y++) {
|
||||
int y0 = y + ty;
|
||||
for (int z = -outsetSize; z <= outsetSize; z++) {
|
||||
if (x * x + y * y + z * z >= brushSizeSquared) {
|
||||
if (y0 + 1 < minY || y0 - 1 > maxY) {
|
||||
continue;
|
||||
}
|
||||
int yy = y * y;
|
||||
int xxyy = xx + yy;
|
||||
if (xxyy >= brushSizeSquared) {
|
||||
continue;
|
||||
}
|
||||
for (int z = -outsetSize; z <= outsetSize; z++) {
|
||||
int z0 = z + tz;
|
||||
int highest = 1;
|
||||
if (xxyy + z * z >= brushSizeSquared || maskFails(editSession, mutable.setComponents(x0, y0, z0))) {
|
||||
continue;
|
||||
}
|
||||
int highest = 1, currentBlockFrequency = 1;
|
||||
BlockState currentState = editSession.getBlock(x0, y0, z0);
|
||||
BlockState highestState = currentState;
|
||||
int currentStateID = currentState.getInternalBlockTypeId();
|
||||
Arrays.fill(frequency, 0);
|
||||
int air = 0;
|
||||
int total = 26;
|
||||
boolean tie = false;
|
||||
for (int ox = -1; ox <= 1; ox++) {
|
||||
for (int oz = -1; oz <= 1; oz++) {
|
||||
for (int oy = -1; oy <= 1; oy++) {
|
||||
if (oy + y0 < minY || oy + y0 > maxY) {
|
||||
if (ox == 0 && oy == 0 && oz == 0) {
|
||||
continue;
|
||||
} else if (oy + y0 < minY || oy + y0 > maxY) {
|
||||
total--;
|
||||
continue;
|
||||
}
|
||||
BlockState state = editSession.getBlock(x0 + ox, y0 + oy, z0 + oz);
|
||||
int count = frequency[state.getInternalBlockTypeId()];
|
||||
boolean masked = maskFails(editSession, mutable.setComponents(x0 + ox, y0 + oy, z0 + oz));
|
||||
BlockState state = masked ? AIR : editSession.getBlock(x0 + ox, y0 + oy, z0 + oz);
|
||||
if (state.getBlockType().getMaterial().isAir()) {
|
||||
air++;
|
||||
}
|
||||
int internalID = state.getInternalBlockTypeId();
|
||||
int count = frequency[internalID];
|
||||
if (internalID == currentStateID) {
|
||||
currentBlockFrequency++;
|
||||
}
|
||||
count++;
|
||||
if (count > highest) {
|
||||
if (count - highest >= minFreqDiff) {
|
||||
highest = count;
|
||||
highestState = state;
|
||||
tie = false;
|
||||
} else if (count == highest) {
|
||||
tie = true;
|
||||
}
|
||||
frequency[state.getInternalBlockTypeId()] = count;
|
||||
frequency[internalID] = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!tie && currentState != highestState) {
|
||||
if (onlyAir) {
|
||||
if (air * 2 - total >= minFreqDiff) {
|
||||
if (!currentState.isAir()) {
|
||||
editSession.setBlock(x0, y0, z0, AIR);
|
||||
}
|
||||
} else if (currentState.isAir() && total - 2 * air >= minFreqDiff) {
|
||||
editSession.setBlock(x0, y0, z0, highestState);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (highest - currentBlockFrequency >= minFreqDiff && !tie && currentState != highestState) {
|
||||
editSession.setBlock(x0, y0, z0, highestState);
|
||||
}
|
||||
}
|
||||
@ -69,5 +135,8 @@ public class BlendBall implements Brush {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean maskFails(EditSession editSession, MutableBlockVector3 mutable) {
|
||||
return mask == null || !mask.test(editSession, mutable);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.fastasyncworldedit.core.function.mask;
|
||||
|
||||
import com.fastasyncworldedit.core.math.BlockVectorSet;
|
||||
import com.fastasyncworldedit.core.math.LocalBlockVectorSet;
|
||||
import com.fastasyncworldedit.core.util.collection.BlockVector3Set;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.mask.AbstractExtentMask;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
@ -11,12 +13,30 @@ import javax.annotation.Nullable;
|
||||
public class CachedMask extends AbstractDelegateMask implements ResettableMask {
|
||||
|
||||
private final boolean hasExtent;
|
||||
private transient BlockVectorSet cache_checked = new BlockVectorSet();
|
||||
private transient BlockVectorSet cache_results = new BlockVectorSet();
|
||||
private transient BlockVector3Set cache_checked;
|
||||
private transient BlockVector3Set cache_results;
|
||||
|
||||
public CachedMask(Mask mask) {
|
||||
this(mask, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CachedMask instance for the given mask
|
||||
*
|
||||
* @param mask Mask to cache results of
|
||||
* @param local If the area will be small
|
||||
* @since TODO
|
||||
*/
|
||||
public CachedMask(Mask mask, boolean local) {
|
||||
super(mask);
|
||||
hasExtent = mask instanceof AbstractExtentMask;
|
||||
if (local) {
|
||||
cache_checked = new LocalBlockVectorSet();
|
||||
cache_results = new LocalBlockVectorSet();
|
||||
} else {
|
||||
cache_checked = new BlockVectorSet();
|
||||
cache_results = new BlockVectorSet();
|
||||
}
|
||||
}
|
||||
|
||||
public static CachedMask cache(Mask mask) {
|
||||
@ -95,7 +115,7 @@ public class CachedMask extends AbstractDelegateMask implements ResettableMask {
|
||||
|
||||
@Override
|
||||
public Mask copy() {
|
||||
return new CachedMask(getMask().copy());
|
||||
return new CachedMask(getMask().copy(), cache_checked instanceof LocalBlockVectorSet);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ import com.fastasyncworldedit.core.command.tool.sweep.SweepBrush;
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder;
|
||||
import com.fastasyncworldedit.core.function.mask.CachedMask;
|
||||
import com.fastasyncworldedit.core.function.mask.IdMask;
|
||||
import com.fastasyncworldedit.core.function.mask.SingleBlockTypeMask;
|
||||
import com.fastasyncworldedit.core.limit.FaweLimit;
|
||||
@ -138,6 +139,7 @@ import java.nio.file.FileSystems;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument;
|
||||
|
||||
/**
|
||||
* Commands to set brush shape.
|
||||
@ -175,10 +177,20 @@ public class BrushCommands {
|
||||
public void blendBallBrush(
|
||||
InjectedValueAccess context,
|
||||
@Arg(desc = "The radius to sample for blending", def = "5")
|
||||
Expression radius
|
||||
Expression radius,
|
||||
@Arg(desc = "Minimum difference in frequency to change block", def = "1")
|
||||
int minFreqDiff,
|
||||
@Switch(name = 'a', desc = "Compare only air vs existing blocks")
|
||||
boolean onlyAir,
|
||||
@ArgFlag(name = 'm', desc = "Mask to limit blocks being considered", def = "")
|
||||
Mask mask
|
||||
) throws WorldEditException {
|
||||
worldEdit.checkMaxBrushRadius(radius);
|
||||
set(context, new BlendBall(), "worldedit.brush.blendball").setSize(radius);
|
||||
checkCommandArgument(minFreqDiff >= 0 && minFreqDiff <= 26, "minFreqDiff not in range 0 <= value <= 26");
|
||||
if (mask != null && !(mask instanceof CachedMask)) {
|
||||
mask = new CachedMask(mask, false);
|
||||
}
|
||||
set(context, new BlendBall(minFreqDiff, onlyAir, (CachedMask) mask), "worldedit.brush.blendball").setSize(radius);
|
||||
}
|
||||
|
||||
@Command(
|
||||
|
Loading…
Reference in New Issue
Block a user