Skip to content

Commit

Permalink
Add clipboard support to //deform and //brush deform
Browse files Browse the repository at this point in the history
  • Loading branch information
TomyLobo committed Apr 5, 2023
1 parent 16efdd2 commit 38233d0
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 85 deletions.
57 changes: 49 additions & 8 deletions worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java
Expand Up @@ -28,6 +28,7 @@
import com.sk89q.worldedit.extension.platform.Watchdog;
import com.sk89q.worldedit.extent.ChangeSetExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.InputExtent;
import com.sk89q.worldedit.extent.MaskingExtent;
import com.sk89q.worldedit.extent.NullExtent;
import com.sk89q.worldedit.extent.TracingExtent;
Expand Down Expand Up @@ -95,6 +96,8 @@
import com.sk89q.worldedit.math.interpolation.Node;
import com.sk89q.worldedit.math.noise.RandomNoise;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.SimpleTransform;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.CylinderRegion;
import com.sk89q.worldedit.regions.EllipsoidRegion;
Expand Down Expand Up @@ -2247,7 +2250,7 @@ public int makeShape(final Region region, final Vector3 zero, final Vector3 unit
final Variable dataVariable = expression.getSlots().getVariable("data")
.orElseThrow(IllegalStateException::new);

final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero);
final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, new SimpleTransform(zero, unit));
expression.setEnvironment(environment);

final int[] timedOut = {0};
Expand Down Expand Up @@ -2314,7 +2317,8 @@ protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial)
*/
public int deformRegion(final Region region, final Vector3 zero, final Vector3 unit, final String expressionString)
throws ExpressionException, MaxChangedBlocksException {
return deformRegion(region, zero, unit, expressionString, WorldEdit.getInstance().getConfiguration().calculationTimeout);
final Transform transform = new SimpleTransform(zero, unit);
return deformRegion(region, transform, expressionString, WorldEdit.getInstance().getConfiguration().calculationTimeout, world, transform);
}

/**
Expand All @@ -2333,11 +2337,33 @@ public int deformRegion(final Region region, final Vector3 zero, final Vector3 u
* @throws ExpressionException thrown on invalid expression input
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
@Deprecated
public int deformRegion(final Region region, final Vector3 zero, final Vector3 unit, final String expressionString,
final int timeout) throws ExpressionException, MaxChangedBlocksException {
final Transform transform = new SimpleTransform(zero, unit);
return deformRegion(region, transform, expressionString, timeout, world, transform);
}

/**
* Deforms the region by a given expression. A deform provides a block's x, y, and z coordinates (possibly scaled)
* to an expression, and then sets the block to the block given by the resulting values of the variables, if they
* have changed.
*
* @param region the region to deform
* @param outputTransform the output coordinate system
* @param expressionString the expression to evaluate for each block
* @param timeout maximum time for the expression to evaluate for each block. -1 for unlimited.
* @param inputExtent the InputExtent to fetch blocks from, for instance a World or a Clipboard
* @param inputTransform the input coordinate system
* @return number of blocks changed
* @throws ExpressionException thrown on invalid expression input
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int deformRegion(final Region region, final Transform outputTransform, final String expressionString,
final int timeout, final InputExtent inputExtent, final Transform inputTransform) throws ExpressionException, MaxChangedBlocksException {
final Expression expression = Expression.compile(expressionString, "x", "y", "z");
expression.optimize();
return deformRegion(region, zero, unit, expression, timeout);
return deformRegion(region, outputTransform, expression, timeout, inputExtent, inputTransform);
}

/**
Expand All @@ -2347,32 +2373,47 @@ public int deformRegion(final Region region, final Vector3 zero, final Vector3 u
* The Expression class is subject to change. Expressions should be provided via the string overload.
* </p>
*/
@Deprecated
public int deformRegion(final Region region, final Vector3 zero, final Vector3 unit, final Expression expression,
final int timeout) throws ExpressionException, MaxChangedBlocksException {
final Transform transform = new SimpleTransform(zero, unit);
return deformRegion(region, transform, expression, timeout, world, transform);
}

/**
* Internal version of {@link EditSession#deformRegion(Region, Vector3, Vector3, String, int)}.
*
* <p>
* The Expression class is subject to change. Expressions should be provided via the string overload.
* </p>
*/
public int deformRegion(final Region region, final Transform outputTransform, final Expression expression,
final int timeout, InputExtent inputExtent, final Transform inputTransform) throws ExpressionException, MaxChangedBlocksException {
final Variable x = expression.getSlots().getVariable("x")
.orElseThrow(IllegalStateException::new);
final Variable y = expression.getSlots().getVariable("y")
.orElseThrow(IllegalStateException::new);
final Variable z = expression.getSlots().getVariable("z")
.orElseThrow(IllegalStateException::new);

final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero);
final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, outputTransform);
expression.setEnvironment(environment);

final DoubleArrayList<BlockVector3, BaseBlock> queue = new DoubleArrayList<>(false);

final Transform outputTransformInverse = outputTransform.inverse();
for (BlockVector3 position : region) {
// transform
final Vector3 scaled = position.toVector3().subtract(zero).divide(unit);
final Vector3 scaled = outputTransformInverse.apply(position.toVector3());

// deform
expression.evaluate(new double[]{scaled.getX(), scaled.getY(), scaled.getZ()}, timeout);

// untransform, round-nearest
final BlockVector3 sourcePosition = environment.toWorld(x.getValue(), y.getValue(), z.getValue());
final BlockVector3 sourcePosition = inputTransform.apply(Vector3.at(x.getValue(), y.getValue(), z.getValue())).add(0.5, 0.5, 0.5).toBlockPoint();

// read block from world
final BaseBlock material = world.getFullBlock(sourcePosition);
// read block from world/clipboard
final BaseBlock material = inputExtent.getFullBlock(sourcePosition);

// queue operation
queue.put(position, material);
Expand Down
Expand Up @@ -502,14 +502,17 @@ public void deform(Player player, LocalSession localSession,
@Switch(name = 'r', desc = "Use the game's coordinate origin")
boolean useRawCoords,
@Switch(name = 'o', desc = "Use the placement position as the origin")
boolean usePlacement) throws WorldEditException {
boolean usePlacement,
@Switch(name = 'l', desc = "Fetch from the clipboard instead of the world")
boolean useClipboard) throws WorldEditException {
Deform deform = new Deform(expression);
if (useRawCoords) {
deform.setMode(Deform.Mode.RAW_COORD);
} else if (usePlacement) {
deform.setMode(Deform.Mode.OFFSET);
deform.setOffset(localSession.getPlacementPosition(player).toVector3());
}
deform.setUseClipboard(useClipboard);
setOperationBasedBrush(player, localSession, radius,
deform, shape, "worldedit.brush.deform");
}
Expand Down
Expand Up @@ -29,6 +29,8 @@
import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.InputExtent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.GroundFunction;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.block.BlockReplace;
Expand All @@ -51,6 +53,9 @@
import com.sk89q.worldedit.math.convolution.HeightMapFilter;
import com.sk89q.worldedit.math.convolution.SnowHeightMap;
import com.sk89q.worldedit.math.noise.RandomNoise;
import com.sk89q.worldedit.math.transform.Identity;
import com.sk89q.worldedit.math.transform.SimpleTransform;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.ConvexPolyhedralRegion;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
Expand Down Expand Up @@ -464,6 +469,44 @@ void regenerate(Actor actor, World world, LocalSession session, EditSession edit
}
}

/**
* Creates a {@link Transform} for the //deform command.
*
* @param useRawCoords Use the game's coordinate origin
* @param offsetPlacement Use the placement's coordinate origin
* @param offsetCenter Use the selection's center as origin
* @param min Minimum of the selection/clipboard
* @param max Maximum of the selection/clipboard
* @param placement Placement position
* @return A transform from the expression coordinate sytem to the world/clipboard coordinate system
*/
private static Transform createTransform(boolean useRawCoords, boolean offsetPlacement, boolean offsetCenter, Vector3 min, Vector3 max, Vector3 placement) {
if (useRawCoords) {
return new Identity();
} else if (offsetPlacement) {
return new SimpleTransform(placement, Vector3.ONE);
} else {
final Vector3 offset = max.add(min).multiply(0.5);

if (offsetCenter) {
return new SimpleTransform(offset, Vector3.ONE);
}

Vector3 scale = max.subtract(offset);

if (scale.getX() == 0) {
scale = scale.withX(1.0);
}
if (scale.getY() == 0) {
scale = scale.withY(1.0);
}
if (scale.getZ() == 0) {
scale = scale.withZ(1.0);
}
return new SimpleTransform(offset, scale);
}
}

@Command(
name = "/deform",
desc = "Deforms a selected region with an expression",
Expand All @@ -482,42 +525,33 @@ public int deform(Actor actor, LocalSession session, EditSession editSession,
@Switch(name = 'o', desc = "Use the placement's coordinate origin")
boolean offsetPlacement,
@Switch(name = 'c', desc = "Use the selection's center as origin")
boolean offsetCenter) throws WorldEditException {
final Vector3 zero;
Vector3 unit;
boolean offsetCenter,
@Switch(name = 'l', desc = "Fetch from the clipboard instead of the world")
boolean useClipboard) throws WorldEditException {

if (useRawCoords) {
zero = Vector3.ZERO;
unit = Vector3.ONE;
} else if (offsetPlacement) {
zero = session.getPlacementPosition(actor).toVector3();
unit = Vector3.ONE;
} else if (offsetCenter) {
final Vector3 min = region.getMinimumPoint().toVector3();
final Vector3 max = region.getMaximumPoint().toVector3();

zero = max.add(min).multiply(0.5);
unit = Vector3.ONE;
} else {
final Vector3 min = region.getMinimumPoint().toVector3();
final Vector3 max = region.getMaximumPoint().toVector3();
final Vector3 min = region.getMinimumPoint().toVector3();
final Vector3 max = region.getMaximumPoint().toVector3();
final Vector3 placement = session.getPlacementPosition(actor).toVector3();

zero = max.add(min).divide(2);
unit = max.subtract(zero);
final Transform outputTransform = createTransform(useRawCoords, offsetPlacement, offsetCenter, min, max, placement);

if (unit.getX() == 0) {
unit = unit.withX(1.0);
}
if (unit.getY() == 0) {
unit = unit.withY(1.0);
}
if (unit.getZ() == 0) {
unit = unit.withZ(1.0);
}
final InputExtent inputExtent;
final Transform inputTransform;
if (useClipboard) {
final Clipboard clipboard = session.getClipboard().getClipboard();
inputExtent = clipboard;

final Vector3 clipboardMin = clipboard.getMinimumPoint().toVector3();
final Vector3 clipboardMax = clipboard.getMaximumPoint().toVector3();

inputTransform = createTransform(useRawCoords, offsetPlacement, offsetCenter, clipboardMin, clipboardMax, clipboardMin);
} else {
inputExtent = editSession.getWorld();
inputTransform = outputTransform;
}

try {
final int affected = editSession.deformRegion(region, zero, unit, String.join(" ", expression), session.getTimeout());
final int affected = editSession.deformRegion(region, outputTransform, String.join(" ", expression), session.getTimeout(), inputExtent, inputTransform);
if (actor instanceof Player) {
((Player) actor).findFreePosition();
}
Expand Down

0 comments on commit 38233d0

Please sign in to comment.