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( CuboidRegion cuboid = new CuboidRegion(
editSession.getWorld(), editSession.getWorld(),
position.subtract(size1, size1, size1), position.subtract(size1, size1, size1),
position.add(size1, size1, size1) position.add(size1, size1, size1),
true
); );
try { try {
editSession.addSchems(cuboid, mask, clipboards, rarity, randomRotate); 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.function.mask.Mask;
import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.ClipboardHolder;
import java.util.List; import java.util.List;
@ -19,29 +20,60 @@ public class SchemGen implements Resource {
private final List<ClipboardHolder> clipboards; private final List<ClipboardHolder> clipboards;
private final boolean randomRotate; private final boolean randomRotate;
private final Mask mask; private final Mask mask;
private final Region region;
private final MutableBlockVector3 mutable = new MutableBlockVector3(); 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) { public SchemGen(Mask mask, Extent extent, List<ClipboardHolder> clipboards, boolean randomRotate) {
this.mask = mask; this.mask = mask;
this.extent = extent; this.extent = extent;
this.clipboards = clipboards; this.clipboards = clipboards;
this.randomRotate = randomRotate; this.randomRotate = randomRotate;
this.region = null;
}
/**
* 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(),
this.extent.getMinY(),
this.extent.getMaxY(),
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 @Override
public boolean spawn(Random random, int x, int z) throws WorldEditException { public boolean spawn(Random random, int x, int z) throws WorldEditException {
mutable.mutX(x); mutable.mutX(x);
mutable.mutZ(z); mutable.mutZ(z);
int y = extent.getNearestSurfaceTerrainBlock( int y = getY(x, z);
x,
z,
mutable.y(),
this.extent.getMinY(),
this.extent.getMaxY(),
Integer.MIN_VALUE,
Integer.MAX_VALUE
);
if (y == Integer.MIN_VALUE || y == Integer.MAX_VALUE) { if (y == Integer.MIN_VALUE || y == Integer.MAX_VALUE) {
return false; return false;
} }
@ -54,7 +86,8 @@ public class SchemGen implements Resource {
if (randomRotate) { if (randomRotate) {
holder.setTransform(new AffineTransform().rotateY(ThreadLocalRandom.current().nextInt(4) * 90)); 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(); Transform transform = holder.getTransform();
if (transform.isIdentity()) { if (transform.isIdentity()) {
clipboard.paste(extent, mutable, false); clipboard.paste(extent, mutable, false);

View File

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

View File

@ -645,10 +645,10 @@ public class BrushCommands {
@CommandPermissions("worldedit.brush.populateschematic") @CommandPermissions("worldedit.brush.populateschematic")
public void scatterSchemBrush( public void scatterSchemBrush(
Player player, InjectedValueAccess context, Player player, InjectedValueAccess context,
@Arg(desc = "Mask")
Mask mask,
@Arg(name = "clipboard", desc = "Clipboard uri") @Arg(name = "clipboard", desc = "Clipboard uri")
String clipboardStr, String clipboardStr,
@Arg(desc = "Mask of block to place on. Defaults to solid blocks.", def = "")
Mask mask,
@Arg(desc = "Expression", def = "30") @Arg(desc = "Expression", def = "30")
Expression radius, Expression radius,
@Arg(desc = "double", def = "50") @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 x the X coordinate
* @param z the Z coordinate * @param z the Z coordinate
@ -225,6 +225,9 @@ public interface Extent extends InputExtent, OutputExtent {
* @return height of highest block found or 'minY' * @return height of highest block found or 'minY'
*/ */
default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY) { 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) { for (int y = maxY; y >= minY; --y) {
BlockState block = getBlock(x, y, z); BlockState block = getBlock(x, y, z);
if (block.getBlockType().getMaterial().isMovementBlocker()) { 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 x the X coordinate
* @param z the Z coordinate * @param z the Z coordinate
@ -245,6 +248,9 @@ public interface Extent extends InputExtent, OutputExtent {
* @return height of highest block found or 'minY' * @return height of highest block found or 'minY'
*/ */
default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, Mask filter) { 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()); maxY = Math.min(maxY, getMaxY());
minY = Math.max(getMinY(), minY); minY = Math.max(getMinY(), minY);
@ -259,9 +265,7 @@ public interface Extent extends InputExtent, OutputExtent {
} }
/** /**
* Returns the nearest surface layer (up/down from start) * Returns the nearest surface layer (up/down from start), where a layer is 1/16th of a block to allow for snow, liquid, etc.
* <p>
* TODO: Someone understand this..?
* *
* @param x x to search from * @param x x to search from
* @param z y to search from * @param z y to search from
@ -271,6 +275,9 @@ public interface Extent extends InputExtent, OutputExtent {
* @return nearest surface layer * @return nearest surface layer
*/ */
default int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { 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 clearanceAbove = maxY - y;
int clearanceBelow = y - minY; int clearanceBelow = y - minY;
int clearance = Math.min(clearanceAbove, clearanceBelow); 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 * @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) { 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)); y = Math.max(minY, Math.min(maxY, y));
int clearanceAbove = maxY - y; int clearanceAbove = maxY - y;
int clearanceBelow = y - minY; int clearanceBelow = y - minY;
@ -438,6 +448,9 @@ public interface Extent extends InputExtent, OutputExtent {
int failedMax, int failedMax,
boolean ignoreAir boolean ignoreAir
) { ) {
maxY = Math.min(maxY, getMaxY());
minY = Math.max(getMinY(), minY);
y = Math.max(minY, Math.min(maxY, y)); y = Math.max(minY, Math.min(maxY, y));
int clearanceAbove = maxY - y; int clearanceAbove = maxY - y;
int clearanceBelow = y - minY; 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 default void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws
WorldEditException { 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 { default void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException {