From d14b267cfd2af76acfb60b4a2dc4312042c1a050 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 24 Aug 2017 22:11:03 +1000 Subject: [PATCH] *More off axis rotation changes Fix off axis rotation for certain angles - Math error when calculating the inverse affine transform Add -a flag to copyPaste brush (rotates based on view) --- .../fawe/object/brush/CopyPastaBrush.java | 28 +++++++++++++++---- .../fawe/object/brush/PopulateSchem.java | 2 +- .../boydti/fawe/object/brush/SpikeBrush.java | 1 + .../fawe/object/brush/StencilBrush.java | 2 +- .../brush/heightmap/ScalableHeightMap.java | 3 +- .../fawe/object/schematic/PNGWriter.java | 2 +- .../java/com/sk89q/worldedit/EditSession.java | 8 +++--- .../worldedit/command/BrushCommands.java | 6 ++-- .../worldedit/command/GenerationCommands.java | 2 +- .../function/operation/ForwardExtentCopy.java | 4 +++ .../math/transform/AffineTransform.java | 10 +++---- .../sk89q/worldedit/regions/CuboidRegion.java | 4 +-- 12 files changed, 47 insertions(+), 25 deletions(-) diff --git a/core/src/main/java/com/boydti/fawe/object/brush/CopyPastaBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/CopyPastaBrush.java index b66b2de3..658a754e 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/CopyPastaBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/CopyPastaBrush.java @@ -24,18 +24,20 @@ import com.sk89q.worldedit.function.visitor.RecursiveVisitor; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.Location; public class CopyPastaBrush implements Brush, ResettableTool { private final LocalSession session; - private final boolean randomRotate; private final Player player; + public boolean autoRotate, randomRotate; - public CopyPastaBrush(Player player, LocalSession session, boolean randomRotate) { + public CopyPastaBrush(Player player, LocalSession session, boolean randomRotate, boolean autoRotate) { session.setClipboard(null); this.player = player; this.session = session; this.randomRotate = randomRotate; + this.autoRotate = autoRotate; } @Override @@ -65,7 +67,7 @@ public class CopyPastaBrush implements Brush, ResettableTool { public boolean test(Vector vector) { if (super.test(vector) && vector.getBlockY() >= minY) { BaseBlock block = editSession.getLazyBlock(vector); - if (block != EditSession.nullBlock) { + if (block.getId() != 0) { builder.add(vector, EditSession.nullBlock, block); return true; } @@ -87,19 +89,33 @@ public class CopyPastaBrush implements Brush, ResettableTool { BBC.COMMAND_COPY.send(fp, blocks); return; } else { + AffineTransform transform = null; if (randomRotate) { + if (transform == null) transform = new AffineTransform(); int rotate = 90 * PseudoRandom.random.nextInt(4); - clipboard.setTransform(rotate != 0 ? new AffineTransform().rotateY(rotate) : new AffineTransform()); + transform = transform.rotateY(rotate); + } + if (autoRotate) { + if (transform == null) transform = new AffineTransform(); + Location loc = editSession.getPlayer().getPlayer().getLocation(); + float yaw = loc.getYaw(); + float pitch = loc.getPitch(); + transform = transform.rotateY((-yaw) % 360); + transform = transform.rotateX(pitch - 90); + } + if (transform != null && !transform.isIdentity()) { + clipboard.setTransform(transform); } Clipboard faweClip = clipboard.getClipboard(); Region region = faweClip.getRegion(); - Vector centerOffset = region.getCenter().subtract(faweClip.getOrigin()); + Operation operation = clipboard - .createPaste(editSession, editSession.getWorld().getWorldData()) + .createPaste(editSession, editSession.getWorldData()) .to(position.add(0, 1, 0)) .ignoreAirBlocks(true) .build(); Operations.completeLegacy(operation); + editSession.flushQueue(); } } } diff --git a/core/src/main/java/com/boydti/fawe/object/brush/PopulateSchem.java b/core/src/main/java/com/boydti/fawe/object/brush/PopulateSchem.java index 76b1f198..0d7304fe 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/PopulateSchem.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/PopulateSchem.java @@ -29,7 +29,7 @@ public class PopulateSchem implements Brush { public void build(EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { new MaskTraverser(mask).reset(editSession); SchemGen gen = new SchemGen(mask, editSession, editSession.getWorldData(), clipboards, randomRotate); - CuboidRegion cuboid = new CuboidRegion(position.subtract(size, size, size), position.add(size, size, size)); + CuboidRegion cuboid = new CuboidRegion(editSession.getWorld(), position.subtract(size, size, size), position.add(size, size, size)); try { editSession.addSchems(cuboid, mask, editSession.getWorldData(), clipboards, rarity, randomRotate); } catch (WorldEditException e) { diff --git a/core/src/main/java/com/boydti/fawe/object/brush/SpikeBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/SpikeBrush.java index eaf6bf14..bc1c3c03 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/SpikeBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/SpikeBrush.java @@ -7,6 +7,7 @@ import com.sk89q.worldedit.command.tool.brush.Brush; import com.sk89q.worldedit.function.pattern.Pattern; public class SpikeBrush implements Brush { + @Override public void build(EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { diff --git a/core/src/main/java/com/boydti/fawe/object/brush/StencilBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/StencilBrush.java index 50783a82..50277f22 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/StencilBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/StencilBrush.java @@ -47,7 +47,7 @@ public class StencilBrush extends HeightBrush { int cutoff = onlyWhite ? maxY : 0; final SolidBlockMask solid = new SolidBlockMask(editSession); final AdjacentAnyMask adjacent = new AdjacentAnyMask(Masks.negate(solid)); - RegionMask region = new RegionMask(new CuboidRegion(position.subtract(size, size, size), position.add(size, size, size))); + RegionMask region = new RegionMask(new CuboidRegion(editSession.getWorld(), position.subtract(size, size, size), position.add(size, size, size))); RecursiveVisitor visitor = new RecursiveVisitor(new Mask() { @Override public boolean test(Vector vector) { diff --git a/core/src/main/java/com/boydti/fawe/object/brush/heightmap/ScalableHeightMap.java b/core/src/main/java/com/boydti/fawe/object/brush/heightmap/ScalableHeightMap.java index efbaedfe..a8c1d6ea 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/heightmap/ScalableHeightMap.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/heightmap/ScalableHeightMap.java @@ -3,7 +3,6 @@ package com.boydti.fawe.object.brush.heightmap; import com.boydti.fawe.object.IntegerPair; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.MathMan; -import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.extent.clipboard.Clipboard; @@ -79,7 +78,7 @@ public class ScalableHeightMap implements com.boydti.fawe.object.brush.heightmap for (int y = minY; y <= maxY; y++) { pos.mutY(y); BaseBlock block = clipboard.getBlock(pos); - if (block != EditSession.nullBlock) { + if (block.getId() != 0) { highestY = y + 1; } } diff --git a/core/src/main/java/com/boydti/fawe/object/schematic/PNGWriter.java b/core/src/main/java/com/boydti/fawe/object/schematic/PNGWriter.java index e7cf5f9a..04072359 100644 --- a/core/src/main/java/com/boydti/fawe/object/schematic/PNGWriter.java +++ b/core/src/main/java/com/boydti/fawe/object/schematic/PNGWriter.java @@ -114,7 +114,7 @@ public class PNGWriter implements ClipboardWriter { mutableTop.mutY(y + 1); mutableRight.mutY(y); mutableLeft.mutY(y); - if (clipboard.getBlock(mutableTop) != EditSession.nullBlock && clipboard.getBlock(mutableRight) != EditSession.nullBlock && clipboard.getBlock(mutableLeft) != EditSession.nullBlock) { + if (clipboard.getBlock(mutableTop).getId() != 0 && clipboard.getBlock(mutableRight) != EditSession.nullBlock && clipboard.getBlock(mutableLeft).getId() != 0 ) { continue; } double cpy = cpy2 - dpxi[y - y0]; diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index f2fbc942..50bf6e95 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -1430,13 +1430,13 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting int freeSpot = startCheckY; for (int y = startCheckY; y <= endY; y++) { if (y < startPerformY) { - if (getLazyBlock(x, y, z) != EditSession.nullBlock) { + if (getLazyBlock(x, y, z).getId() != 0) { freeSpot = y + 1; } continue; } BaseBlock block = getLazyBlock(x, y, z); - if (block != EditSession.nullBlock) { + if (block.getId() != 0) { if (freeSpot != y) { setBlock(x, freeSpot, z, block); setBlock(x, y, z, replace); @@ -2217,11 +2217,11 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting return makeCylinder(pos, block, radiusX, radiusZ, height, 0, filled); } - public int makeHollowCylinder(Vector pos, final Pattern block, double radiusX, double radiusZ, int height, int thickness) { + public int makeHollowCylinder(Vector pos, final Pattern block, double radiusX, double radiusZ, int height, double thickness) { return makeCylinder(pos, block, radiusX, radiusZ, height, thickness, false); } - private int makeCylinder(Vector pos, final Pattern block, double radiusX, double radiusZ, int height, int thickness, final boolean filled) { + private int makeCylinder(Vector pos, final Pattern block, double radiusX, double radiusZ, int height, double thickness, final boolean filled) { radiusX += 0.5; radiusZ += 0.5; diff --git a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index ce2c842e..ae7cfb53 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -783,17 +783,19 @@ public class BrushCommands extends MethodCommands { help = "Left click the base of an object to copy.\n" + "Right click to paste\n" + "The -r flag Will apply random rotation on paste\n" + + "The -a flag Will apply auto view based rotation on paste\n" + "Note: Works well with the clipboard scroll action\n" + "Video: https://www.youtube.com/watch?v=RPZIaTbqoZw", min = 0, max = 1 ) @CommandPermissions("worldedit.brush.copy") - public BrushSettings copy(Player player, LocalSession session, @Optional("5") double radius, @Switch('r') boolean rotate, CommandContext context) throws WorldEditException { + public BrushSettings copy(Player player, LocalSession session, @Optional("5") double radius, @Switch('r') boolean randomRotate, @Switch('a') boolean autoRotate, CommandContext context) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); player.print(BBC.getPrefix() + BBC.BRUSH_COPY.f(radius)); + return get(context) - .setBrush(new CopyPastaBrush(player, session, rotate)) + .setBrush(new CopyPastaBrush(player, session, randomRotate, autoRotate)) .setSize(radius); } diff --git a/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index ad7dffc6..7204ee9a 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -184,7 +184,7 @@ public class GenerationCommands extends MethodCommands { ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) - public void hcyl(FawePlayer fp, Player player, LocalSession session, EditSession editSession, Pattern pattern, Vector2D radius, @Optional("1") int height, @Range(min = 1) @Optional("1") int thickness, CommandContext context) throws WorldEditException, ParameterException { + public void hcyl(FawePlayer fp, Player player, LocalSession session, EditSession editSession, Pattern pattern, Vector2D radius, @Optional("1") int height, @Range(min = 1) @Optional("1") double thickness, CommandContext context) throws WorldEditException, ParameterException { double max = MathMan.max(radius.getBlockX(), radius.getBlockZ()); worldEdit.checkMaxRadius(max); fp.checkConfirmationRadius(getArguments(context), (int) max); diff --git a/core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java b/core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java index a91b29ab..9a8e6108 100644 --- a/core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java +++ b/core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java @@ -25,6 +25,7 @@ import com.boydti.fawe.object.extent.BlockTranslateExtent; import com.boydti.fawe.object.extent.PositionTransformExtent; import com.boydti.fawe.object.function.block.BiomeCopy; import com.boydti.fawe.object.function.block.SimpleBlockCopy; +import com.boydti.fawe.util.MaskTraverser; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; @@ -249,8 +250,10 @@ public class ForwardExtentCopy implements Operation { } else { queue = null; } + Extent finalDest = destination; Vector translation = to.subtract(from); + if (!translation.equals(Vector.ZERO)) { finalDest = new BlockTranslateExtent(finalDest, translation.getBlockX(), translation.getBlockY(), translation.getBlockZ()); } @@ -264,6 +267,7 @@ public class ForwardExtentCopy implements Operation { RegionFunction copy = new SimpleBlockCopy(transExt, finalDest); if (sourceMask != Masks.alwaysTrue()) { + new MaskTraverser(sourceMask).reset(transExt); copy = new RegionMaskingFilter(sourceMask, copy); } if (sourceFunction != null) { diff --git a/core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java b/core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java index 7c3b7b58..24635af1 100644 --- a/core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java +++ b/core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java @@ -150,7 +150,7 @@ public class AffineTransform implements Transform, Serializable { * * @return the determinant of the transform. */ - private double determinant() { + public double determinant() { return m00 * (m11 * m22 - m12 * m21) - m01 * (m10 * m22 - m20 * m12) + m02 * (m10 * m21 - m20 * m11); } @@ -163,17 +163,17 @@ public class AffineTransform implements Transform, Serializable { double det = this.determinant(); return new AffineTransform( (m11 * m22 - m21 * m12) / det, - (m21 * m01 - m01 * m22) / det, + (m02 * m21 - m22 * m01) / det, (m01 * m12 - m11 * m02) / det, (m01 * (m22 * m13 - m12 * m23) + m02 * (m11 * m23 - m21 * m13) - m03 * (m11 * m22 - m21 * m12)) / det, - (m20 * m12 - m10 * m22) / det, + (m12 * m20 - m22 * m10) / det, (m00 * m22 - m20 * m02) / det, - (m10 * m02 - m00 * m12) / det, + (m02 * m10 - m12 * m00) / det, (m00 * (m12 * m23 - m22 * m13) - m02 * (m10 * m23 - m20 * m13) + m03 * (m10 * m22 - m20 * m12)) / det, (m10 * m21 - m20 * m11) / det, - (m20 * m01 - m00 * m21) / det, + (m01 * m20 - m21 * m00) / det, (m00 * m11 - m10 * m01) / det, (m00 * (m21 * m13 - m11 * m23) + m01 * (m10 * m23 - m20 * m13) - m03 * (m10 * m21 - m20 * m11)) / det); diff --git a/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index 021aa515..8ef51af3 100644 --- a/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -137,8 +137,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { if (pos1 == null || pos2 == null) { return; } - pos1 = pos1.clampY(0, world == null ? 255 : world.getMaxY()); - pos2 = pos2.clampY(0, world == null ? 255 : world.getMaxY()); + pos1 = pos1.clampY(world == null ? Integer.MIN_VALUE : 0, world == null ? Integer.MAX_VALUE : world.getMaxY()); + pos2 = pos2.clampY(world == null ? Integer.MIN_VALUE : 0, world == null ? Integer.MAX_VALUE : world.getMaxY()); Vector min = getMinimumPoint(); Vector max = getMaximumPoint(); minX = min.getBlockX();