Skip to content

Commit

Permalink
Add the trim command (#2278)
Browse files Browse the repository at this point in the history
* Add the trim command

Fixes #1629

* Fix issues from PR review

---------

Co-authored-by: Madeline Miller <[email protected]>
  • Loading branch information
haykam821 and me4502 authored Jun 24, 2023
1 parent a3a5b07 commit b5b29a2
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,16 @@
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.block.BlockDistributionCounter;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.MaskIntersection;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.mask.RegionMask;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.internal.annotation.Chunk3d;
import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.MultiDirection;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.regions.RegionSelector;
Expand Down Expand Up @@ -504,6 +508,141 @@ private BlockVector3[] getChangesForEachDir(int amount, boolean onlyHorizontal,
return changes.build().map(v -> v.multiply(amount)).toArray(BlockVector3[]::new);
}

@Command(
name = "/trim",
desc = "Minimize the selection to encompass matching blocks"
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.trim")
public void trim(Actor actor, World world, LocalSession session,
@Arg(desc = "Mask of blocks to keep within the selection", def = "#existing")
Mask mask) throws WorldEditException {
// Avoid checking blocks outside the original region but within the cuboid region
Region originalRegion = session.getSelection(world);
if (!(originalRegion instanceof CuboidRegion)) {
mask = new MaskIntersection(new RegionMask(originalRegion), mask);
}
// Memoize the mask to reduce duplicated lookups
mask = Masks.memoize(mask);

// Result region will be cuboid
CuboidRegion region = originalRegion.getBoundingBox();

BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();

int minY = 0;
boolean found = false;

outer: for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
BlockVector3 vec = BlockVector3.at(x, y, z);

if (mask.test(vec)) {
found = true;
minY = y;

break outer;
}
}
}
}

// If anything was found in the first pass, then the remaining variables are guaranteed to be set
if (!found) {
throw new StopExecutionException(TranslatableComponent.of(
"worldedit.trim.no-blocks"));
}

int maxY = minY;

outer: for (int y = max.getBlockY(); y > minY; y--) {
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
BlockVector3 vec = BlockVector3.at(x, y, z);

if (mask.test(vec)) {
maxY = y;
break outer;
}
}
}
}

int minX = 0;

outer: for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
for (int y = minY; y <= maxY; y++) {
BlockVector3 vec = BlockVector3.at(x, y, z);

if (mask.test(vec)) {
minX = x;
break outer;
}
}
}
}

int maxX = minX;

outer: for (int x = max.getBlockX(); x > minX; x--) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
for (int y = minY; y <= maxY; y++) {
BlockVector3 vec = BlockVector3.at(x, y, z);

if (mask.test(vec)) {
maxX = x;
break outer;
}
}
}
}

int minZ = 0;

outer: for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
BlockVector3 vec = BlockVector3.at(x, y, z);

if (mask.test(vec)) {
minZ = z;
break outer;
}
}
}
}

int maxZ = minZ;

outer: for (int z = max.getBlockZ(); z > minZ; z--) {
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
BlockVector3 vec = BlockVector3.at(x, y, z);

if (mask.test(vec)) {
maxZ = z;
break outer;
}
}
}
}

final CuboidRegionSelector selector;
if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) {
selector = new ExtendingCuboidRegionSelector(world, BlockVector3.at(minX, minY, minZ), BlockVector3.at(maxX, maxY, maxZ));
} else {
selector = new CuboidRegionSelector(world, BlockVector3.at(minX, minY, minZ), BlockVector3.at(maxX, maxY, maxZ));
}
session.setRegionSelector(world, selector);

session.getRegionSelector(world).learnChanges();
session.getRegionSelector(world).explainRegionAdjust(actor, session);
actor.printInfo(TranslatableComponent.of("worldedit.trim.trim"));
}

@Command(
name = "/size",
desc = "Get information about the selection"
Expand Down
2 changes: 2 additions & 0 deletions worldedit-core/src/main/resources/lang/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@
"worldedit.shift.shifted": "Region shifted.",
"worldedit.outset.outset": "Region outset.",
"worldedit.inset.inset": "Region inset.",
"worldedit.trim.trim": "Region trimmed.",
"worldedit.trim.no-blocks": "No blocks matched the trim mask.",
"worldedit.size.offset": "Offset: {0}",
"worldedit.size.type": "Type: {0}",
"worldedit.size.size": "Size: {0}",
Expand Down

0 comments on commit b5b29a2

Please sign in to comment.