fix: improve SchemGen, allow null mask (reordered command args) (#2817)

- fixes #2815
This commit is contained in:
Jordan 2024-07-23 19:53:12 +02:00 committed by GitHub
parent b5ff328218
commit ddacb976e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 67 additions and 20 deletions

View File

@ -24,7 +24,8 @@ public record PopulateSchem(Mask mask, List<ClipboardHolder> clipboards, int rar
CuboidRegion cuboid = new CuboidRegion(
editSession.getWorld(),
position.subtract(size1, size1, size1),
position.add(size1, size1, size1)
position.add(size1, size1, size1),
true
);
try {
editSession.addSchems(cuboid, mask, clipboards, rarity, randomRotate);

View File

@ -7,6 +7,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
import java.util.List;
@ -19,21 +20,38 @@ public class SchemGen implements Resource {
private final List<ClipboardHolder> clipboards;
private final boolean randomRotate;
private final Mask mask;
private final Region region;
private final MutableBlockVector3 mutable = new MutableBlockVector3();
/**
* @deprecated Use {@link SchemGen#SchemGen(Mask, Extent, List, boolean, Region)}
*/
@Deprecated(forRemoval = true, since = "TODO")
public SchemGen(Mask mask, Extent extent, List<ClipboardHolder> clipboards, boolean randomRotate) {
this.mask = mask;
this.extent = extent;
this.clipboards = clipboards;
this.randomRotate = randomRotate;
this.region = null;
}
@Override
public boolean spawn(Random random, int x, int z) throws WorldEditException {
mutable.mutX(x);
mutable.mutZ(z);
int y = extent.getNearestSurfaceTerrainBlock(
/**
* New instance. Places a schematic on terrain at a given x,z when appropriate
*
* @since TODO
*/
public SchemGen(Mask mask, Extent extent, List<ClipboardHolder> clipboards, boolean randomRotate, Region region) {
this.mask = mask;
this.extent = extent;
this.clipboards = clipboards;
this.randomRotate = randomRotate;
this.region = region;
}
private int getY(int x, int z) {
if (region == null) {
return extent.getNearestSurfaceTerrainBlock(
x,
z,
mutable.y(),
@ -42,6 +60,20 @@ public class SchemGen implements Resource {
Integer.MIN_VALUE,
Integer.MAX_VALUE
);
} else {
int y = extent.getHighestTerrainBlock(x, z, region.getMinimumY(), region.getMaximumY(), mask);
if (y == region.getMinimumY() && !extent.getBlock(x, y, z).getMaterial().isMovementBlocker()) {
return Integer.MIN_VALUE;
}
return y;
}
}
@Override
public boolean spawn(Random random, int x, int z) throws WorldEditException {
mutable.mutX(x);
mutable.mutZ(z);
int y = getY(x, z);
if (y == Integer.MIN_VALUE || y == Integer.MAX_VALUE) {
return false;
}
@ -54,7 +86,8 @@ public class SchemGen implements Resource {
if (randomRotate) {
holder.setTransform(new AffineTransform().rotateY(ThreadLocalRandom.current().nextInt(4) * 90));
}
Clipboard clipboard = holder.getClipboard();
Clipboard clipboard = holder.getClipboards().size() == 1 ? holder.getClipboard() :
holder.getClipboards().get(ThreadLocalRandom.current().nextInt(clipboards.size()));
Transform transform = holder.getTransform();
if (transform.isIdentity()) {
clipboard.paste(extent, mutable, false);

View File

@ -3881,7 +3881,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
@Override
public void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws
WorldEditException {
spawnResource(region, new SchemGen(mask, this, clipboards, rotate), rarity, 1);
spawnResource(region, new SchemGen(mask, this, clipboards, rotate, region), rarity, 1);
}
@Override

View File

@ -645,10 +645,10 @@ public class BrushCommands {
@CommandPermissions("worldedit.brush.populateschematic")
public void scatterSchemBrush(
Player player, InjectedValueAccess context,
@Arg(desc = "Mask")
Mask mask,
@Arg(name = "clipboard", desc = "Clipboard uri")
String clipboardStr,
@Arg(desc = "Mask of block to place on. Defaults to solid blocks.", def = "")
Mask mask,
@Arg(desc = "Expression", def = "30")
Expression radius,
@Arg(desc = "double", def = "50")

View File

@ -216,7 +216,7 @@ public interface Extent extends InputExtent, OutputExtent {
*/
/**
* Returns the highest solid 'terrain' block.
* Returns the highest solid 'terrain' (movement-blocking) block.
*
* @param x the X coordinate
* @param z the Z coordinate
@ -225,6 +225,9 @@ public interface Extent extends InputExtent, OutputExtent {
* @return height of highest block found or 'minY'
*/
default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY) {
maxY = Math.min(maxY, getMaxY());
minY = Math.max(getMinY(), minY);
for (int y = maxY; y >= minY; --y) {
BlockState block = getBlock(x, y, z);
if (block.getBlockType().getMaterial().isMovementBlocker()) {
@ -235,7 +238,7 @@ public interface Extent extends InputExtent, OutputExtent {
}
/**
* Returns the highest solid 'terrain' block.
* Returns the highest block matching the given mask.
*
* @param x the X coordinate
* @param z the Z coordinate
@ -245,6 +248,9 @@ public interface Extent extends InputExtent, OutputExtent {
* @return height of highest block found or 'minY'
*/
default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, Mask filter) {
if (filter == null) {
return getHighestTerrainBlock(x, z, minY, maxY);
}
maxY = Math.min(maxY, getMaxY());
minY = Math.max(getMinY(), minY);
@ -259,9 +265,7 @@ public interface Extent extends InputExtent, OutputExtent {
}
/**
* Returns the nearest surface layer (up/down from start)
* <p>
* TODO: Someone understand this..?
* Returns the nearest surface layer (up/down from start), where a layer is 1/16th of a block to allow for snow, liquid, etc.
*
* @param x x to search from
* @param z y to search from
@ -271,6 +275,9 @@ public interface Extent extends InputExtent, OutputExtent {
* @return nearest surface layer
*/
default int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
maxY = Math.min(maxY, getMaxY());
minY = Math.max(getMinY(), minY);
int clearanceAbove = maxY - y;
int clearanceBelow = y - minY;
int clearance = Math.min(clearanceAbove, clearanceBelow);
@ -331,6 +338,9 @@ public interface Extent extends InputExtent, OutputExtent {
* @return The y value of the nearest terrain block
*/
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
maxY = Math.min(maxY, getMaxY());
minY = Math.max(getMinY(), minY);
y = Math.max(minY, Math.min(maxY, y));
int clearanceAbove = maxY - y;
int clearanceBelow = y - minY;
@ -438,6 +448,9 @@ public interface Extent extends InputExtent, OutputExtent {
int failedMax,
boolean ignoreAir
) {
maxY = Math.min(maxY, getMaxY());
minY = Math.max(getMinY(), minY);
y = Math.max(minY, Math.min(maxY, y));
int clearanceAbove = maxY - y;
int clearanceBelow = y - minY;
@ -494,7 +507,7 @@ public interface Extent extends InputExtent, OutputExtent {
default void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws
WorldEditException {
spawnResource(region, new SchemGen(mask, this, clipboards, rotate), rarity, 1);
spawnResource(region, new SchemGen(mask, this, clipboards, rotate, region), rarity, 1);
}
default void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException {