From 62e94d16ec10017417bf399da26cbc7a5bd346f8 Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Wed, 8 Mar 2023 01:03:43 +0100 Subject: [PATCH 01/11] Rename offset arguments on //deform, //generate and //generatebiome to offsetPlacement --- .../com/sk89q/worldedit/command/GenerationCommands.java | 8 ++++---- .../java/com/sk89q/worldedit/command/RegionCommands.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index 1c7bb86655..bf5076848c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -370,7 +370,7 @@ public int generate(Actor actor, LocalSession session, EditSession editSession, @Switch(name = 'r', desc = "Use the game's coordinate origin") boolean useRawCoords, @Switch(name = 'o', desc = "Use the placement's coordinate origin") - boolean offset, + boolean offsetPlacement, @Switch(name = 'c', desc = "Use the selection's center as origin") boolean offsetCenter) throws WorldEditException { @@ -380,7 +380,7 @@ public int generate(Actor actor, LocalSession session, EditSession editSession, if (useRawCoords) { zero = Vector3.ZERO; unit = Vector3.ONE; - } else if (offset) { + } else if (offsetPlacement) { zero = session.getPlacementPosition(actor).toVector3(); unit = Vector3.ONE; } else if (offsetCenter) { @@ -439,7 +439,7 @@ public int generateBiome(Actor actor, LocalSession session, EditSession editSess @Switch(name = 'r', desc = "Use the game's coordinate origin") boolean useRawCoords, @Switch(name = 'o', desc = "Use the placement's coordinate origin") - boolean offset, + boolean offsetPlacement, @Switch(name = 'c', desc = "Use the selection's center as origin") boolean offsetCenter) throws WorldEditException { final Vector3 zero; @@ -448,7 +448,7 @@ public int generateBiome(Actor actor, LocalSession session, EditSession editSess if (useRawCoords) { zero = Vector3.ZERO; unit = Vector3.ONE; - } else if (offset) { + } else if (offsetPlacement) { zero = session.getPlacementPosition(actor).toVector3(); unit = Vector3.ONE; } else if (offsetCenter) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index 92284f25bd..f32e80c218 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -495,7 +495,7 @@ public int deform(Actor actor, LocalSession session, EditSession editSession, @Switch(name = 'r', desc = "Use the game's coordinate origin") boolean useRawCoords, @Switch(name = 'o', desc = "Use the placement's coordinate origin") - boolean offset, + boolean offsetPlacement, @Switch(name = 'c', desc = "Use the selection's center as origin") boolean offsetCenter) throws WorldEditException { final Vector3 zero; @@ -504,7 +504,7 @@ public int deform(Actor actor, LocalSession session, EditSession editSession, if (useRawCoords) { zero = Vector3.ZERO; unit = Vector3.ONE; - } else if (offset) { + } else if (offsetPlacement) { zero = session.getPlacementPosition(actor).toVector3(); unit = Vector3.ONE; } else if (offsetCenter) { From be558a4a8d0c6c64ea1a6926963acd2d0df37f11 Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Wed, 8 Mar 2023 04:59:45 +0100 Subject: [PATCH 02/11] More accurate comments --- .../src/main/java/com/sk89q/worldedit/EditSession.java | 5 +++-- .../regions/shape/WorldEditExpressionEnvironment.java | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index b442163190..631c0ddb49 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -2437,12 +2437,13 @@ public int deformRegion(final Region region, final Vector3 zero, final Vector3 u final Vector3 targetPosition = targetBlockPosition.toVector3(); environment.setCurrentBlock(targetPosition); - // offset, scale + // transform from target coordinates final Vector3 scaled = targetPosition.subtract(zero).divide(unit); - // transform + // deform expression.evaluate(new double[]{ scaled.x(), scaled.y(), scaled.z() }, timeout); + // transform to source coordinates, round-nearest final BlockVector3 sourcePosition = environment.toWorld(x.value(), y.value(), z.value()); // read block from world diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java index 56763d3bc2..da1825259d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java @@ -39,7 +39,6 @@ public WorldEditExpressionEnvironment(Extent extent, Vector3 unit, Vector3 zero) } public BlockVector3 toWorld(double x, double y, double z) { - // unscale, unoffset, round-nearest return Vector3.at(x, y, z).multiply(unit).add(zero2).toBlockPoint(); } From a97f205479d4cb6ca8481be946e76b7f2fee4773 Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Thu, 18 Jul 2024 08:04:08 +0200 Subject: [PATCH 03/11] Give some variables more appropriate names --- .../java/com/sk89q/worldedit/EditSession.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 631c0ddb49..9e418ffb47 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -2327,7 +2327,7 @@ public int makeShape(final Region region, final Vector3 zero, final Vector3 unit protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { final Vector3 current = Vector3.at(x, y, z); environment.setCurrentBlock(current); - final Vector3 scaled = current.subtract(zero).divide(unit); + final Vector3 inputPosition = current.subtract(zero).divide(unit); try { int[] legacy = LegacyMapper.getInstance().getLegacyFromBlock(defaultMaterial.toImmutableState()); @@ -2339,7 +2339,7 @@ protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) dataVar = legacy[1]; } } - if (expression.evaluate(new double[]{ scaled.x(), scaled.y(), scaled.z(), typeVar, dataVar}, timeout) <= 0) { + if (expression.evaluate(new double[]{ inputPosition.x(), inputPosition.y(), inputPosition.z(), typeVar, dataVar}, timeout) <= 0) { return null; } int newType = (int) typeVariable.value(); @@ -2438,10 +2438,10 @@ public int deformRegion(final Region region, final Vector3 zero, final Vector3 u environment.setCurrentBlock(targetPosition); // transform from target coordinates - final Vector3 scaled = targetPosition.subtract(zero).divide(unit); + final Vector3 inputPosition = targetPosition.subtract(zero).divide(unit); // deform - expression.evaluate(new double[]{ scaled.x(), scaled.y(), scaled.z() }, timeout); + expression.evaluate(new double[]{ inputPosition.x(), inputPosition.y(), inputPosition.z() }, timeout); // transform to source coordinates, round-nearest final BlockVector3 sourcePosition = environment.toWorld(x.value(), y.value(), z.value()); @@ -2455,11 +2455,11 @@ public int deformRegion(final Region region, final Vector3 zero, final Vector3 u int affected = 0; for (Map.Entry entry : queue) { - BlockVector3 position = entry.getKey(); + BlockVector3 targetPosition = entry.getKey(); BaseBlock material = entry.getValue(); - // set at new position - if (setBlock(position, material)) { + // set at new targetPosition + if (setBlock(targetPosition, material)) { ++affected; } } @@ -2773,10 +2773,10 @@ public int makeBiomeShape(final Region region, final Vector3 zero, final Vector3 protected BiomeType getBiome(int x, int y, int z, BiomeType defaultBiomeType) { final Vector3 current = Vector3.at(x, y, z); environment.setCurrentBlock(current); - final Vector3 scaled = current.subtract(zero).divide(unit); + final Vector3 inputPosition = current.subtract(zero).divide(unit); try { - if (expression.evaluate(new double[]{ scaled.x(), scaled.y(), scaled.z() }, timeout) <= 0) { + if (expression.evaluate(new double[]{ inputPosition.x(), inputPosition.y(), inputPosition.z() }, timeout) <= 0) { return null; } From 49b6895f495fdfae4db19cb2b4b6f088d1b5984c Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Sat, 13 Jul 2024 14:35:16 +0200 Subject: [PATCH 04/11] Add ScaleAndTranslateTransform class --- .../transform/ScaleAndTranslateTransform.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/ScaleAndTranslateTransform.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/ScaleAndTranslateTransform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/ScaleAndTranslateTransform.java new file mode 100644 index 0000000000..93630a8688 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/ScaleAndTranslateTransform.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.math.transform; + +import com.sk89q.worldedit.math.Vector3; + +/** + * A more light-weight {@link Transform} than {@link AffineTransform}, supporting only translation and scaling. + */ +public record ScaleAndTranslateTransform(Vector3 offset, Vector3 scale) implements Transform { + + @Override + public boolean isIdentity() { + return offset.equals(Vector3.ZERO) && scale.equals(Vector3.ONE); + } + + @Override + public Vector3 apply(Vector3 input) { + return input.multiply(scale).add(offset); + } + + @Override + public Transform inverse() { + return new Transform() { + @Override + public boolean isIdentity() { + return ScaleAndTranslateTransform.this.isIdentity(); + } + + @Override + public Vector3 apply(Vector3 input) { + return input.subtract(offset).divide(scale); + } + + @Override + public Transform inverse() { + return ScaleAndTranslateTransform.this; + } + + @Override + public Transform combine(Transform other) { + return new CombinedTransform(this, other); + } + }; + } + + @Override + public Transform combine(Transform other) { + return new CombinedTransform(this, other); + } +} From 9f4fae4ea7c208c22785ca4dd57f4af1db571dca Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Sat, 13 Jul 2024 14:41:53 +0200 Subject: [PATCH 05/11] Use ScaleAndTranslateTransform in WorldEditExpressionEnvironment --- .../shape/WorldEditExpressionEnvironment.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java index da1825259d..a27dd863a5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java @@ -23,23 +23,28 @@ import com.sk89q.worldedit.internal.expression.ExpressionEnvironment; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.ScaleAndTranslateTransform; +import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.world.registry.LegacyMapper; public class WorldEditExpressionEnvironment implements ExpressionEnvironment { - private final Vector3 unit; - private final Vector3 zero2; + private final Transform transform; private Vector3 current = Vector3.ZERO; private final Extent extent; + @Deprecated public WorldEditExpressionEnvironment(Extent extent, Vector3 unit, Vector3 zero) { + this(extent, new ScaleAndTranslateTransform(zero, unit)); + } + + public WorldEditExpressionEnvironment(Extent extent, Transform transform) { this.extent = extent; - this.unit = unit; - this.zero2 = zero.add(0.5, 0.5, 0.5); + this.transform = transform; } public BlockVector3 toWorld(double x, double y, double z) { - return Vector3.at(x, y, z).multiply(unit).add(zero2).toBlockPoint(); + return transform.apply(Vector3.at(x, y, z)).add(0.5, 0.5, 0.5).toBlockPoint(); } public Vector3 toWorldRel(double x, double y, double z) { From 17e28bca866b73d976f63aafc309574e522ed050 Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Sat, 13 Jul 2024 21:00:50 +0200 Subject: [PATCH 06/11] Use ScaleAndTranslateTransform in everything using WorldEditExpressionEnvironment --- .../java/com/sk89q/worldedit/EditSession.java | 102 ++++++++++++++++-- .../worldedit/command/GenerationCommands.java | 74 ++----------- .../worldedit/command/RegionCommands.java | 37 +------ .../parser/mask/ExpressionMaskParser.java | 4 +- .../worldedit/function/factory/Deform.java | 30 +++--- .../internal/util/TransformUtil.java | 82 ++++++++++++++ 6 files changed, 202 insertions(+), 127 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 9e418ffb47..06c4f2a050 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -94,6 +94,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.ScaleAndTranslateTransform; +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; @@ -2267,6 +2269,7 @@ public List> getBlockDistribution(Region region, boolean s * @throws ExpressionException if there is a problem with the expression * @throws MaxChangedBlocksException if the maximum block change limit is exceeded */ + @Deprecated public int makeShape(final Region region, final Vector3 zero, final Vector3 unit, final Pattern pattern, final String expressionString, final boolean hollow) throws ExpressionException, MaxChangedBlocksException { @@ -2287,12 +2290,32 @@ public int makeShape(final Region region, final Vector3 zero, final Vector3 unit * @throws ExpressionException if there is a problem with the expression * @throws MaxChangedBlocksException if the maximum block change limit is exceeded */ + @Deprecated public int makeShape(final Region region, final Vector3 zero, final Vector3 unit, final Pattern pattern, final String expressionString, final boolean hollow, final int timeout) throws ExpressionException, MaxChangedBlocksException { + return makeShape(region, new ScaleAndTranslateTransform(zero, unit), pattern, expressionString, hollow, timeout); + } + + /** + * Generate a shape for the given expression. + * + * @param region the region to generate the shape in + * @param transform the transformation for x/y/z variables + * @param pattern the default material to make the shape from + * @param expressionString the expression defining the shape + * @param hollow whether the shape should be hollow + * @param timeout the time, in milliseconds, to wait for each expression evaluation before halting it. -1 to disable + * @return number of blocks changed + * @throws ExpressionException if there is a problem with the expression + * @throws MaxChangedBlocksException if the maximum block change limit is exceeded + */ + public int makeShape(final Region region, + Transform transform, final Pattern pattern, final String expressionString, final boolean hollow, final int timeout) + throws ExpressionException, MaxChangedBlocksException { final Expression expression = Expression.compile(expressionString, "x", "y", "z", "type", "data"); expression.optimize(); - return makeShape(region, zero, unit, pattern, expression, hollow, timeout); + return makeShape(region, transform, pattern, expression, hollow, timeout); } /** @@ -2302,9 +2325,23 @@ public int makeShape(final Region region, final Vector3 zero, final Vector3 unit * The Expression class is subject to change. Expressions should be provided via the string overload. *

*/ + @Deprecated public int makeShape(final Region region, final Vector3 zero, final Vector3 unit, final Pattern pattern, final Expression expression, final boolean hollow, final int timeout) throws ExpressionException, MaxChangedBlocksException { + return makeShape(region, new ScaleAndTranslateTransform(zero, unit), pattern, expression, hollow, timeout); + } + + /** + * Internal version of {@link EditSession#makeShape(Region, Vector3, Vector3, Pattern, String, boolean, int)}. + * + *

+ * The Expression class is subject to change. Expressions should be provided via the string overload. + *

+ */ + public int makeShape(final Region region, Transform transform, + final Pattern pattern, final Expression expression, final boolean hollow, final int timeout) + throws ExpressionException, MaxChangedBlocksException { expression.getSlots().getVariable("x") .orElseThrow(IllegalStateException::new); @@ -2318,16 +2355,17 @@ 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, transform); expression.setEnvironment(environment); final int[] timedOut = {0}; + final Transform transformInverse = transform.inverse(); final ArbitraryShape shape = new ArbitraryShape(region) { @Override protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { final Vector3 current = Vector3.at(x, y, z); environment.setCurrentBlock(current); - final Vector3 inputPosition = current.subtract(zero).divide(unit); + final Vector3 inputPosition = transformInverse.apply(current); try { int[] legacy = LegacyMapper.getInstance().getLegacyFromBlock(defaultMaterial.toImmutableState()); @@ -2384,9 +2422,10 @@ protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) * @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) throws ExpressionException, MaxChangedBlocksException { - return deformRegion(region, zero, unit, expressionString, WorldEdit.getInstance().getConfiguration().calculationTimeout); + return deformRegion(region, new ScaleAndTranslateTransform(zero, unit), expressionString, WorldEdit.getInstance().getConfiguration().calculationTimeout); } /** @@ -2405,11 +2444,31 @@ 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 ScaleAndTranslateTransform(zero, unit); + return deformRegion(region, transform, expressionString, timeout); + } + + /** + * 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 transform the 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. + * @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 transform, final String expressionString, + final int timeout) throws ExpressionException, MaxChangedBlocksException { final Expression expression = Expression.compile(expressionString, "x", "y", "z"); expression.optimize(); - return deformRegion(region, zero, unit, expression, timeout); + return deformRegion(region, transform, expression, timeout); } /** @@ -2419,8 +2478,21 @@ 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. *

*/ + @Deprecated public int deformRegion(final Region region, final Vector3 zero, final Vector3 unit, final Expression expression, final int timeout) throws ExpressionException, MaxChangedBlocksException { + return deformRegion(region, new ScaleAndTranslateTransform(zero, unit), expression, timeout); + } + + /** + * Internal version of {@link EditSession#deformRegion(Region, Vector3, Vector3, String, int)}. + * + *

+ * The Expression class is subject to change. Expressions should be provided via the string overload. + *

+ */ + public int deformRegion(final Region region, final Transform transform, final Expression expression, + final int timeout) throws ExpressionException, MaxChangedBlocksException { final Variable x = expression.getSlots().getVariable("x") .orElseThrow(IllegalStateException::new); final Variable y = expression.getSlots().getVariable("y") @@ -2428,23 +2500,25 @@ public int deformRegion(final Region region, final Vector3 zero, final Vector3 u final Variable z = expression.getSlots().getVariable("z") .orElseThrow(IllegalStateException::new); - final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero); + final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, transform); expression.setEnvironment(environment); final DoubleArrayList queue = new DoubleArrayList<>(false); + final Transform transformInverse = transform.inverse(); for (BlockVector3 targetBlockPosition : region) { final Vector3 targetPosition = targetBlockPosition.toVector3(); environment.setCurrentBlock(targetPosition); // transform from target coordinates - final Vector3 inputPosition = targetPosition.subtract(zero).divide(unit); + final Vector3 inputPosition = transformInverse.apply(targetPosition); // deform expression.evaluate(new double[]{ inputPosition.x(), inputPosition.y(), inputPosition.z() }, timeout); + final Vector3 outputPosition = Vector3.at(x.value(), y.value(), z.value()); // transform to source coordinates, round-nearest - final BlockVector3 sourcePosition = environment.toWorld(x.value(), y.value(), z.value()); + final BlockVector3 sourcePosition = transform.apply(outputPosition).add(0.5, 0.5, 0.5).toBlockPoint(); // read block from world final BaseBlock material = world.getFullBlock(sourcePosition); @@ -2752,28 +2826,36 @@ private void recurseHollow(Region region, BlockVector3 origin, Set } } + @Deprecated public int makeBiomeShape(final Region region, final Vector3 zero, final Vector3 unit, final BiomeType biomeType, final String expressionString, final boolean hollow) throws ExpressionException { return makeBiomeShape(region, zero, unit, biomeType, expressionString, hollow, WorldEdit.getInstance().getConfiguration().calculationTimeout); } + @Deprecated public int makeBiomeShape(final Region region, final Vector3 zero, final Vector3 unit, final BiomeType biomeType, final String expressionString, final boolean hollow, final int timeout) throws ExpressionException { + return makeBiomeShape(region, new ScaleAndTranslateTransform(zero, unit), biomeType, expressionString, hollow, timeout); + } + + public int makeBiomeShape(final Region region, Transform transform, final BiomeType biomeType, + final String expressionString, final boolean hollow, final int timeout) throws ExpressionException { final Expression expression = Expression.compile(expressionString, "x", "y", "z"); expression.optimize(); final EditSession editSession = this; - final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(editSession, unit, zero); + final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(editSession, transform); expression.setEnvironment(environment); AtomicInteger timedOut = new AtomicInteger(); + final Transform transformInverse = transform.inverse(); final ArbitraryBiomeShape shape = new ArbitraryBiomeShape(region) { @Override protected BiomeType getBiome(int x, int y, int z, BiomeType defaultBiomeType) { final Vector3 current = Vector3.at(x, y, z); environment.setCurrentBlock(current); - final Vector3 inputPosition = current.subtract(zero).divide(unit); + final Vector3 inputPosition = transformInverse.apply(current); try { if (expression.evaluate(new double[]{ inputPosition.x(), inputPosition.y(), inputPosition.z() }, timeout) <= 0) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index bf5076848c..7cd222f742 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -32,8 +32,9 @@ import com.sk89q.worldedit.internal.annotation.Radii; import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.internal.util.TransformUtil; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.formatting.text.TextComponent; @@ -373,42 +374,10 @@ public int generate(Actor actor, LocalSession session, EditSession editSession, boolean offsetPlacement, @Switch(name = 'c', desc = "Use the selection's center as origin") boolean offsetCenter) throws WorldEditException { - - final Vector3 zero; - Vector3 unit; - - 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(); - - zero = max.add(min).multiply(0.5); - unit = max.subtract(zero); - - if (unit.x() == 0) { - unit = unit.withX(1.0); - } - if (unit.y() == 0) { - unit = unit.withY(1.0); - } - if (unit.z() == 0) { - unit = unit.withZ(1.0); - } - } + final Transform transform = TransformUtil.createTransformForExpressionCommand(actor, session, region, useRawCoords, offsetPlacement, offsetCenter); try { - final int affected = editSession.makeShape(region, zero, unit, pattern, String.join(" ", expression), hollow, session.getTimeout()); + final int affected = editSession.makeShape(region, transform, pattern, String.join(" ", expression), hollow, session.getTimeout()); if (actor instanceof Player) { ((Player) actor).findFreePosition(); } @@ -442,41 +411,10 @@ public int generateBiome(Actor actor, LocalSession session, EditSession editSess boolean offsetPlacement, @Switch(name = 'c', desc = "Use the selection's center as origin") boolean offsetCenter) throws WorldEditException { - final Vector3 zero; - Vector3 unit; - - 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(); - - zero = max.add(min).multiply(0.5); - unit = max.subtract(zero); - - if (unit.x() == 0) { - unit = unit.withX(1.0); - } - if (unit.y() == 0) { - unit = unit.withY(1.0); - } - if (unit.z() == 0) { - unit = unit.withZ(1.0); - } - } + final Transform transform = TransformUtil.createTransformForExpressionCommand(actor, session, region, useRawCoords, offsetPlacement, offsetCenter); try { - final int affected = editSession.makeBiomeShape(region, zero, unit, target, String.join(" ", expression), hollow, session.getTimeout()); + final int affected = editSession.makeBiomeShape(region, transform, target, String.join(" ", expression), hollow, session.getTimeout()); actor.printInfo(TranslatableComponent.of("worldedit.generatebiome.changed", TextComponent.of(affected))); return affected; } catch (ExpressionException e) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index f32e80c218..d1b8efa0d1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -47,13 +47,14 @@ import com.sk89q.worldedit.internal.annotation.Offset; import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.internal.util.TransformUtil; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.convolution.GaussianKernel; import com.sk89q.worldedit.math.convolution.HeightMap; 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.Transform; import com.sk89q.worldedit.regions.ConvexPolyhedralRegion; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; @@ -498,41 +499,11 @@ public int deform(Actor actor, LocalSession session, EditSession editSession, boolean offsetPlacement, @Switch(name = 'c', desc = "Use the selection's center as origin") boolean offsetCenter) throws WorldEditException { - final Vector3 zero; - Vector3 unit; - - 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(); - - zero = max.add(min).divide(2); - unit = max.subtract(zero); - if (unit.x() == 0) { - unit = unit.withX(1.0); - } - if (unit.y() == 0) { - unit = unit.withY(1.0); - } - if (unit.z() == 0) { - unit = unit.withZ(1.0); - } - } + final Transform transform = TransformUtil.createTransformForExpressionCommand(actor, session, region, useRawCoords, offsetPlacement, offsetCenter); try { - final int affected = editSession.deformRegion(region, zero, unit, String.join(" ", expression), session.getTimeout()); + final int affected = editSession.deformRegion(region, transform, String.join(" ", expression), session.getTimeout()); if (actor instanceof Player) { ((Player) actor).findFreePosition(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java index c58af7d566..09f684cf2e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java @@ -27,7 +27,7 @@ import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.registry.InputParser; -import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.Identity; import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import com.sk89q.worldedit.session.SessionOwner; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; @@ -58,7 +58,7 @@ public Mask parseFromInput(String input, ParserContext context) throws InputPars try { Expression exp = Expression.compile(input.substring(1), "x", "y", "z"); WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment( - context.requireExtent(), Vector3.ONE, Vector3.ZERO); + context.requireExtent(), new Identity()); exp.setEnvironment(env); if (context.getActor() != null) { SessionOwner owner = context.getActor(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java index 017e8b3a3e..5103770fdd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java @@ -33,6 +33,9 @@ import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.Identity; +import com.sk89q.worldedit.math.transform.ScaleAndTranslateTransform; +import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.NullRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.formatting.text.Component; @@ -118,18 +121,16 @@ public String toString() { @Override public Operation createFromContext(final EditContext context) { - final Vector3 zero; - Vector3 unit; Region region = firstNonNull(context.getRegion(), this.region); + final Transform transform; switch (mode) { case UNIT_CUBE: final Vector3 min = region.getMinimumPoint().toVector3(); final Vector3 max = region.getMaximumPoint().toVector3(); - - zero = max.add(min).multiply(0.5); - unit = max.subtract(zero); + final Vector3 zero = max.add(min).multiply(0.5); + Vector3 unit = max.subtract(zero); if (unit.x() == 0) { unit = unit.withX(1.0); @@ -140,27 +141,28 @@ public Operation createFromContext(final EditContext context) { if (unit.z() == 0) { unit = unit.withZ(1.0); } + + transform = new ScaleAndTranslateTransform(zero, unit); break; + case RAW_COORD: - zero = Vector3.ZERO; - unit = Vector3.ONE; + transform = new Identity(); break; + case OFFSET: default: - zero = offset; - unit = Vector3.ONE; + transform = new ScaleAndTranslateTransform(offset, Vector3.ONE); + break; } - LocalSession session = context.getSession(); - return new DeformOperation(context.getDestination(), region, zero, unit, expression, + return new DeformOperation(context.getDestination(), region, transform, expression, session == null ? WorldEdit.getInstance().getConfiguration().calculationTimeout : session.getTimeout()); } private record DeformOperation( Extent destination, Region region, - Vector3 zero, - Vector3 unit, + Transform transform, Expression expression, int timeout ) implements Operation { @@ -168,7 +170,7 @@ private record DeformOperation( public Operation resume(RunContext run) throws WorldEditException { try { // TODO: Move deformation code - ((EditSession) destination).deformRegion(region, zero, unit, expression, timeout); + ((EditSession) destination).deformRegion(region, transform, expression, timeout); return null; } catch (ExpressionException e) { throw new RuntimeException("Failed to execute expression", e); // TODO: Better exception to throw here? diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java new file mode 100644 index 0000000000..b5efce5a94 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java @@ -0,0 +1,82 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.internal.util; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.Identity; +import com.sk89q.worldedit.math.transform.ScaleAndTranslateTransform; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.Region; + +/** + * Various internal utility methods related to {@link Transform}s. + */ +public final class TransformUtil { + + private TransformUtil() { + } + + /** + * Creates a {@link Transform} for various expression commands. + * + * @param actor Actor that ran the command + * @param session Session that the command was run in + * @param region Selection that the command was run in + * @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 + * @return A transform from the expression coordinate system to the raw coordinate system + */ + public static Transform createTransformForExpressionCommand(Actor actor, LocalSession session, Region region, boolean useRawCoords, boolean offsetPlacement, boolean offsetCenter) throws IncompleteRegionException { + if (useRawCoords) { + return new Identity(); + } + + if (offsetPlacement) { + final Vector3 placement = session.getPlacementPosition(actor).toVector3(); + + return new ScaleAndTranslateTransform(placement, Vector3.ONE); + } + + final Vector3 min = region.getMinimumPoint().toVector3(); + final Vector3 max = region.getMaximumPoint().toVector3(); + final Vector3 center = max.add(min).multiply(0.5); + + if (offsetCenter) { + return new ScaleAndTranslateTransform(center, Vector3.ONE); + } + + Vector3 scale = max.subtract(center); + + if (scale.x() == 0) { + scale = scale.withX(1.0); + } + if (scale.y() == 0) { + scale = scale.withY(1.0); + } + if (scale.z() == 0) { + scale = scale.withZ(1.0); + } + return new ScaleAndTranslateTransform(center, scale); + } +} From cb59fab8f9820f448f1c21232544e95ab1099c4d Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Sun, 14 Jul 2024 00:36:53 +0200 Subject: [PATCH 07/11] Add inputExtent parameter and separate in/outputTransform for deformRegion --- .../java/com/sk89q/worldedit/EditSession.java | 47 ++++++++++++++----- .../worldedit/command/RegionCommands.java | 4 +- .../worldedit/function/factory/Deform.java | 3 +- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 06c4f2a050..ddceae30d7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -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; @@ -2451,6 +2452,28 @@ public int deformRegion(final Region region, final Vector3 zero, final Vector3 u return deformRegion(region, transform, expressionString, timeout); } + /** + * 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 targetTransform the target 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 sourceExtent the InputExtent to fetch blocks from, for instance a World or a Clipboard + * @param sourceTransform the source 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 targetTransform, final String expressionString, + final int timeout, InputExtent sourceExtent, Transform sourceTransform) throws ExpressionException, MaxChangedBlocksException { + final Expression expression = Expression.compile(expressionString, "x", "y", "z"); + expression.optimize(); + return deformRegion(region, targetTransform, expression, timeout, sourceExtent, sourceTransform); + } + /** * 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 @@ -2464,11 +2487,10 @@ 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 Transform transform, final String expressionString, final int timeout) throws ExpressionException, MaxChangedBlocksException { - final Expression expression = Expression.compile(expressionString, "x", "y", "z"); - expression.optimize(); - return deformRegion(region, transform, expression, timeout); + return deformRegion(region, transform, expressionString, timeout, world, transform); } /** @@ -2481,7 +2503,8 @@ public int deformRegion(final Region region, final Transform transform, final St @Deprecated public int deformRegion(final Region region, final Vector3 zero, final Vector3 unit, final Expression expression, final int timeout) throws ExpressionException, MaxChangedBlocksException { - return deformRegion(region, new ScaleAndTranslateTransform(zero, unit), expression, timeout); + final Transform transform = new ScaleAndTranslateTransform(zero, unit); + return deformRegion(region, transform, expression, timeout, world, transform); } /** @@ -2491,8 +2514,8 @@ 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. *

*/ - public int deformRegion(final Region region, final Transform transform, final Expression expression, - final int timeout) throws ExpressionException, MaxChangedBlocksException { + public int deformRegion(final Region region, final Transform targetTransform, final Expression expression, + final int timeout, InputExtent sourceExtent, final Transform sourceTransform) throws ExpressionException, MaxChangedBlocksException { final Variable x = expression.getSlots().getVariable("x") .orElseThrow(IllegalStateException::new); final Variable y = expression.getSlots().getVariable("y") @@ -2500,28 +2523,28 @@ public int deformRegion(final Region region, final Transform transform, final Ex final Variable z = expression.getSlots().getVariable("z") .orElseThrow(IllegalStateException::new); - final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, transform); + final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, targetTransform); expression.setEnvironment(environment); final DoubleArrayList queue = new DoubleArrayList<>(false); - final Transform transformInverse = transform.inverse(); + final Transform targetTransformInverse = targetTransform.inverse(); for (BlockVector3 targetBlockPosition : region) { final Vector3 targetPosition = targetBlockPosition.toVector3(); environment.setCurrentBlock(targetPosition); // transform from target coordinates - final Vector3 inputPosition = transformInverse.apply(targetPosition); + final Vector3 inputPosition = targetTransformInverse.apply(targetPosition); // deform expression.evaluate(new double[]{ inputPosition.x(), inputPosition.y(), inputPosition.z() }, timeout); final Vector3 outputPosition = Vector3.at(x.value(), y.value(), z.value()); // transform to source coordinates, round-nearest - final BlockVector3 sourcePosition = transform.apply(outputPosition).add(0.5, 0.5, 0.5).toBlockPoint(); + final BlockVector3 sourcePosition = sourceTransform.apply(outputPosition).add(0.5, 0.5, 0.5).toBlockPoint(); - // read block from world - final BaseBlock material = world.getFullBlock(sourcePosition); + // read block from source extent (e.g. world/clipboard) + final BaseBlock material = sourceExtent.getFullBlock(sourcePosition); // queue operation queue.put(targetBlockPosition, material); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index d1b8efa0d1..c24c4cb1de 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.InputExtent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.RegionFunction; @@ -501,9 +502,10 @@ public int deform(Actor actor, LocalSession session, EditSession editSession, boolean offsetCenter) throws WorldEditException { final Transform transform = TransformUtil.createTransformForExpressionCommand(actor, session, region, useRawCoords, offsetPlacement, offsetCenter); + final InputExtent inputExtent = editSession.getWorld(); try { - final int affected = editSession.deformRegion(region, transform, String.join(" ", expression), session.getTimeout()); + final int affected = editSession.deformRegion(region, transform, String.join(" ", expression), session.getTimeout(), inputExtent, transform); if (actor instanceof Player) { ((Player) actor).findFreePosition(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java index 5103770fdd..6ae469b4c1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java @@ -170,7 +170,8 @@ private record DeformOperation( public Operation resume(RunContext run) throws WorldEditException { try { // TODO: Move deformation code - ((EditSession) destination).deformRegion(region, transform, expression, timeout); + final EditSession editSession = (EditSession) destination; + editSession.deformRegion(region, transform, expression, timeout, editSession.getWorld(), transform); return null; } catch (ExpressionException e) { throw new RuntimeException("Failed to execute expression", e); // TODO: Better exception to throw here? From 2e0ecdb02be70ecaa0911aca1901409276783d7e Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Sun, 14 Jul 2024 09:14:00 +0200 Subject: [PATCH 08/11] Add clipboard support to //deform --- .../worldedit/command/RegionCommands.java | 25 ++++++++++++++++--- .../internal/util/TransformUtil.java | 23 ++++++++++++++--- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index c24c4cb1de..3469a765f0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -33,6 +33,7 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.InputExtent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +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; @@ -50,6 +51,7 @@ import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.util.TransformUtil; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.convolution.GaussianKernel; import com.sk89q.worldedit.math.convolution.HeightMap; import com.sk89q.worldedit.math.convolution.HeightMapFilter; @@ -499,13 +501,28 @@ 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 { + boolean offsetCenter, + @Switch(name = 'l', desc = "Fetch from the clipboard instead of the world") + boolean useClipboard) throws WorldEditException { + final Transform targetTransform = TransformUtil.createTransformForExpressionCommand(actor, session, region, useRawCoords, offsetPlacement, offsetCenter); - final Transform transform = TransformUtil.createTransformForExpressionCommand(actor, session, region, useRawCoords, offsetPlacement, offsetCenter); - final InputExtent inputExtent = editSession.getWorld(); + final InputExtent sourceExtent; + final Transform sourceTransform; + if (useClipboard) { + final Clipboard clipboard = session.getClipboard().getClipboard(); + sourceExtent = clipboard; + + final Vector3 clipboardMin = clipboard.getMinimumPoint().toVector3(); + final Vector3 clipboardMax = clipboard.getMaximumPoint().toVector3(); + + sourceTransform = TransformUtil.createTransformForExpressionCommand(useRawCoords, offsetPlacement, offsetCenter, clipboardMin, clipboardMax, clipboardMin); + } else { + sourceExtent = editSession.getWorld(); + sourceTransform = targetTransform; + } try { - final int affected = editSession.deformRegion(region, transform, String.join(" ", expression), session.getTimeout(), inputExtent, transform); + final int affected = editSession.deformRegion(region, targetTransform, String.join(" ", expression), session.getTimeout(), sourceExtent, sourceTransform); if (actor instanceof Player) { ((Player) actor).findFreePosition(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java index b5efce5a94..9c3851c20d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java @@ -48,18 +48,33 @@ private TransformUtil() { * @return A transform from the expression coordinate system to the raw coordinate system */ public static Transform createTransformForExpressionCommand(Actor actor, LocalSession session, Region region, boolean useRawCoords, boolean offsetPlacement, boolean offsetCenter) throws IncompleteRegionException { + final Vector3 placement = session.getPlacementPosition(actor).toVector3(); + final Vector3 min = region.getMinimumPoint().toVector3(); + final Vector3 max = region.getMaximumPoint().toVector3(); + + return createTransformForExpressionCommand(useRawCoords, offsetPlacement, offsetCenter, min, max, placement); + } + + /** + * Creates a {@link Transform} for the //deform command with clipboard support. + * + * @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 system to the world/clipboard coordinate system + */ + public static Transform createTransformForExpressionCommand(boolean useRawCoords, boolean offsetPlacement, boolean offsetCenter, Vector3 min, Vector3 max, Vector3 placement) { if (useRawCoords) { return new Identity(); } if (offsetPlacement) { - final Vector3 placement = session.getPlacementPosition(actor).toVector3(); - return new ScaleAndTranslateTransform(placement, Vector3.ONE); } - final Vector3 min = region.getMinimumPoint().toVector3(); - final Vector3 max = region.getMaximumPoint().toVector3(); final Vector3 center = max.add(min).multiply(0.5); if (offsetCenter) { From 08252ee0264b11cb3f4d0a26046255a85b54d6c8 Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Sun, 14 Jul 2024 22:53:10 +0200 Subject: [PATCH 09/11] //brush deform: Use ScaleAndTranslateTransform in everything using WorldEditExpressionEnvironment --- .../worldedit/function/factory/Deform.java | 36 +++---------------- .../internal/util/TransformUtil.java | 24 +++++++++++++ 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java index 6ae469b4c1..ff05b2966f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java @@ -32,9 +32,8 @@ import com.sk89q.worldedit.function.operation.RunContext; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.internal.util.TransformUtil; import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.math.transform.Identity; -import com.sk89q.worldedit.math.transform.ScaleAndTranslateTransform; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.NullRegion; import com.sk89q.worldedit.regions.Region; @@ -123,37 +122,10 @@ public String toString() { public Operation createFromContext(final EditContext context) { Region region = firstNonNull(context.getRegion(), this.region); + final Vector3 min = region.getMinimumPoint().toVector3(); + final Vector3 max = region.getMaximumPoint().toVector3(); - final Transform transform; - switch (mode) { - case UNIT_CUBE: - final Vector3 min = region.getMinimumPoint().toVector3(); - final Vector3 max = region.getMaximumPoint().toVector3(); - final Vector3 zero = max.add(min).multiply(0.5); - Vector3 unit = max.subtract(zero); - - if (unit.x() == 0) { - unit = unit.withX(1.0); - } - if (unit.y() == 0) { - unit = unit.withY(1.0); - } - if (unit.z() == 0) { - unit = unit.withZ(1.0); - } - - transform = new ScaleAndTranslateTransform(zero, unit); - break; - - case RAW_COORD: - transform = new Identity(); - break; - - case OFFSET: - default: - transform = new ScaleAndTranslateTransform(offset, Vector3.ONE); - break; - } + final Transform transform = TransformUtil.createTransformForExpressionCommand(mode, min, max, offset); LocalSession session = context.getSession(); return new DeformOperation(context.getDestination(), region, transform, expression, session == null ? WorldEdit.getInstance().getConfiguration().calculationTimeout : session.getTimeout()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java index 9c3851c20d..33da69d6a2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/TransformUtil.java @@ -22,6 +22,7 @@ import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.function.factory.Deform; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.Identity; import com.sk89q.worldedit.math.transform.ScaleAndTranslateTransform; @@ -94,4 +95,27 @@ public static Transform createTransformForExpressionCommand(boolean useRawCoords } return new ScaleAndTranslateTransform(center, scale); } + + /** + * Creates a {@link Transform} for the //deform command with clipboard support. + * + * @param mode The coordinate mode to use + * @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 system to the world/clipboard coordinate system + */ + public static Transform createTransformForExpressionCommand(Deform.Mode mode, Vector3 min, Vector3 max, Vector3 placement) { + switch (mode) { + case UNIT_CUBE: + return createTransformForExpressionCommand(false, false, false, min, max, placement); + + case RAW_COORD: + return createTransformForExpressionCommand(true, false, false, min, max, placement); + + case OFFSET: + default: + return createTransformForExpressionCommand(false, true, false, min, max, placement); + } + } } From 556152300cac7d94e6397eb32a6f5c15c9b87626 Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Sun, 14 Jul 2024 23:02:05 +0200 Subject: [PATCH 10/11] //brush deform: Add inputExtent parameter and separate in/outputTransform for deformRegion --- .../com/sk89q/worldedit/function/factory/Deform.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java index ff05b2966f..984d3514dd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.InputExtent; import com.sk89q.worldedit.extent.NullExtent; import com.sk89q.worldedit.function.Contextual; import com.sk89q.worldedit.function.EditContext; @@ -127,23 +128,26 @@ public Operation createFromContext(final EditContext context) { final Transform transform = TransformUtil.createTransformForExpressionCommand(mode, min, max, offset); LocalSession session = context.getSession(); + EditSession editSession = (EditSession) context.getDestination(); return new DeformOperation(context.getDestination(), region, transform, expression, - session == null ? WorldEdit.getInstance().getConfiguration().calculationTimeout : session.getTimeout()); + session == null ? WorldEdit.getInstance().getConfiguration().calculationTimeout : session.getTimeout(), editSession.getWorld(), transform); } private record DeformOperation( Extent destination, Region region, - Transform transform, + Transform targetTransform, Expression expression, - int timeout + int timeout, + InputExtent sourceExtent, + Transform sourceTransform ) implements Operation { @Override public Operation resume(RunContext run) throws WorldEditException { try { // TODO: Move deformation code final EditSession editSession = (EditSession) destination; - editSession.deformRegion(region, transform, expression, timeout, editSession.getWorld(), transform); + editSession.deformRegion(region, targetTransform, expression, timeout, sourceExtent, sourceTransform); return null; } catch (ExpressionException e) { throw new RuntimeException("Failed to execute expression", e); // TODO: Better exception to throw here? From adbee4e7567c44844fd09239db886ee5845f0e62 Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Wed, 17 Jul 2024 08:03:17 +0200 Subject: [PATCH 11/11] Add clipboard to //brush deform --- .../com/sk89q/worldedit/LocalSession.java | 10 +++++ .../worldedit/command/BrushCommands.java | 5 ++- .../worldedit/function/factory/Deform.java | 37 +++++++++++++++++-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 7eb1a73837..b89da133c7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -69,6 +69,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.TimeZone; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; @@ -451,6 +452,15 @@ public ClipboardHolder getClipboard() throws EmptyClipboardException { return clipboard; } + /** + * Gets the clipboard. + * + * @return clipboard + */ + public Optional getClipboardOptional() { + return Optional.ofNullable(clipboard); + } + /** * Sets the clipboard. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 120ba27db8..f2155b3e96 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -506,7 +506,9 @@ 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); @@ -514,6 +516,7 @@ public void deform(Player player, LocalSession localSession, deform.setMode(Deform.Mode.OFFSET); deform.setOffset(localSession.getPlacementPosition(player).toVector3()); } + deform.setUseClipboard(useClipboard); setOperationBasedBrush(player, localSession, radius, deform, shape, "worldedit.brush.deform"); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java index 984d3514dd..6136a969b2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java @@ -27,6 +27,7 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.InputExtent; import com.sk89q.worldedit.extent.NullExtent; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.Contextual; import com.sk89q.worldedit.function.EditContext; import com.sk89q.worldedit.function.operation.Operation; @@ -38,11 +39,14 @@ import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.NullRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import java.util.Optional; + import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull; @@ -53,6 +57,7 @@ public class Deform implements Contextual { private final Expression expression; private Mode mode; private Vector3 offset = Vector3.ZERO; + private boolean useClipboard; public Deform(String expression) { this(new NullExtent(), new NullRegion(), expression); @@ -114,6 +119,14 @@ public void setOffset(Vector3 offset) { this.offset = offset; } + public boolean useClipboard() { + return useClipboard; + } + + public void setUseClipboard(boolean useClipboard) { + this.useClipboard = useClipboard; + } + @Override public String toString() { return "deformation of " + expression.getSource(); @@ -126,11 +139,29 @@ public Operation createFromContext(final EditContext context) { final Vector3 min = region.getMinimumPoint().toVector3(); final Vector3 max = region.getMaximumPoint().toVector3(); - final Transform transform = TransformUtil.createTransformForExpressionCommand(mode, min, max, offset); LocalSession session = context.getSession(); EditSession editSession = (EditSession) context.getDestination(); - return new DeformOperation(context.getDestination(), region, transform, expression, - session == null ? WorldEdit.getInstance().getConfiguration().calculationTimeout : session.getTimeout(), editSession.getWorld(), transform); + final Optional clipboardOptional = Optional.ofNullable(session) + .flatMap(LocalSession::getClipboardOptional) + .map(ClipboardHolder::getClipboard); + + final Transform targetTransform = TransformUtil.createTransformForExpressionCommand(mode, min, max, offset); + final InputExtent sourceExtent; + final Transform sourceTransform; + if (useClipboard && clipboardOptional.isPresent()) { + final Clipboard clipboard = clipboardOptional.get(); + final Vector3 clipboardMin = clipboard.getMinimumPoint().toVector3(); + final Vector3 clipboardMax = clipboard.getMaximumPoint().toVector3(); + + sourceExtent = clipboard; + sourceTransform = TransformUtil.createTransformForExpressionCommand(mode, clipboardMin, clipboardMax, offset); + } else { + sourceExtent = editSession.getWorld(); + sourceTransform = targetTransform; + } + + return new DeformOperation(context.getDestination(), region, targetTransform, expression, + session == null ? WorldEdit.getInstance().getConfiguration().calculationTimeout : session.getTimeout(), sourceExtent, sourceTransform); } private record DeformOperation(