diff --git a/.github/workflows/label-merge-conflicts.yaml b/.github/workflows/label-merge-conflicts.yaml index d189f5520..fa6f3d72d 100644 --- a/.github/workflows/label-merge-conflicts.yaml +++ b/.github/workflows/label-merge-conflicts.yaml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Label conflicting PRs - uses: eps1lon/actions-label-merge-conflict@v2.1.0 + uses: eps1lon/actions-label-merge-conflict@v3.0.0 with: dirtyLabel: "unresolved-merge-conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 5a7e91d1f..5222025da 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.github.johnrengelman:shadow:8.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.11") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.12") } kotlin { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a6acb6c2e..f6d16d21d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.1.20" +towny = "0.100.1.24" plotsquared = "7.3.6" # Third party @@ -43,7 +43,7 @@ serverlib = "2.3.4" ## Internal text-adapter = "3.0.6" text = "3.0.4" -piston = "0.5.8" +piston = "0.5.10" # Tests mockito = "5.11.0" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd4917..e6441136f 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a80b22ce5..b82aa23a4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index f18ef582f..3e2bbe382 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240316.193646-135") + the().paperDevBundle("1.20.4-R0.1-20240329.175742-144") compileOnly(libs.paperlib) } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java index 7ea15e421..5e6c9ac52 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java @@ -5,6 +5,7 @@ import com.fastasyncworldedit.core.function.mask.RadiusMask; import com.fastasyncworldedit.core.function.mask.SurfaceMask; import com.fastasyncworldedit.core.math.BlockVectorSet; import com.fastasyncworldedit.core.math.LocalBlockVectorSet; +import com.fastasyncworldedit.core.util.collection.BlockVector3Set; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.command.tool.brush.Brush; @@ -64,8 +65,9 @@ public class ScatterBrush implements Brush { length = 1; visited.add(position); } - LocalBlockVectorSet placed = new LocalBlockVectorSet(); - placed.setOffset(position.getX(), position.getZ()); + BlockVector3 patternSize = pattern.size(); + BlockVector3Set placed = BlockVector3Set.getAppropriateVectorSet(patternSize.add(distance, distance, distance)); + placed.setOffset(position.getX(), position.getY(), position.getZ()); int maxFails = 1000; for (int i = 0; i < count; i++) { int index = ThreadLocalRandom.current().nextInt(length); @@ -88,7 +90,20 @@ public class ScatterBrush implements Brush { finish(editSession, placed, position, pattern, size); } + /** + * @deprecated Use {@link ScatterBrush#finish(EditSession, BlockVector3Set, BlockVector3, Pattern, double)} + */ + @Deprecated(forRemoval = true, since = "TODO") public void finish(EditSession editSession, LocalBlockVectorSet placed, BlockVector3 pos, Pattern pattern, double size) { + finish(editSession, (BlockVector3Set) placed, pos, pattern, size); + } + + /** + * Complete the scatter brush process. + * + * @since TODO + */ + public void finish(EditSession editSession, BlockVector3Set placed, BlockVector3 pos, Pattern pattern, double size) { } public boolean canApply(BlockVector3 pos) { @@ -99,8 +114,23 @@ public class ScatterBrush implements Brush { return surface.direction(pt); } + + /** + * @deprecated Use {@link ScatterBrush#apply(EditSession, BlockVector3Set, BlockVector3, Pattern, double)} + */ + @Deprecated(forRemoval = true, since = "TODO") public void apply(EditSession editSession, LocalBlockVectorSet placed, BlockVector3 pt, Pattern p, double size) throws MaxChangedBlocksException { + apply(editSession, (BlockVector3Set) placed, pt, p, size); + } + + /** + * Apply the scatter brush to a given position + * + * @since TODO + */ + public void apply(EditSession editSession, BlockVector3Set placed, BlockVector3 pt, Pattern p, double size) throws + MaxChangedBlocksException { editSession.setBlock(pt, p); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java index 58fdb4997..41b36e12c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java @@ -3,6 +3,7 @@ package com.fastasyncworldedit.core.command.tool.brush; import com.fastasyncworldedit.core.function.mask.SurfaceMask; import com.fastasyncworldedit.core.math.LocalBlockVectorSet; import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.util.collection.BlockVector3Set; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.function.mask.Mask; @@ -24,7 +25,7 @@ public class ShatterBrush extends ScatterBrush { @Override public void apply( final EditSession editSession, - final LocalBlockVectorSet placed, + final BlockVector3Set placed, final BlockVector3 position, Pattern p, double size @@ -34,7 +35,7 @@ public class ShatterBrush extends ScatterBrush { @Override public void finish( EditSession editSession, - LocalBlockVectorSet placed, + BlockVector3Set placed, final BlockVector3 position, Pattern pattern, double size diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java index e57ccb490..c266fd544 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java @@ -19,12 +19,9 @@ import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.function.Supplier; @@ -80,28 +77,18 @@ public class MultiBatchProcessor implements IBatchProcessor { @Override public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { - Map> ordered = new HashMap<>(); + Map> ordered = new HashMap<>(); IChunkSet chunkSet = set; for (IBatchProcessor processor : processors) { if (processor.getScope() != ProcessorScope.ADDING_BLOCKS) { - ordered.merge( - processor.getScope().intValue(), - new HashSet<>(Collections.singleton(processor)), - (existing, theNew) -> { - existing.add(processor); - return existing; - } - ); + ordered.computeIfAbsent(processor.getScope().intValue(), k -> new ArrayList<>()) + .add(processor); continue; } chunkSet = processSet(processor, chunk, get, chunkSet); } - if (ordered.size() > 0) { - for (int i = 1; i <= 4; i++) { - Set processors = ordered.get(i); - if (processors == null) { - continue; - } + if (!ordered.isEmpty()) { + for (List processors : ordered.values()) { for (IBatchProcessor processor : processors) { chunkSet = processSet(processor, chunk, get, chunkSet); if (chunkSet == null) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java index a9c1ec962..638872ea8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.function.pattern; import com.sk89q.worldedit.function.pattern.AbstractPattern; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.expression.EvaluationException; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; @@ -57,4 +58,9 @@ public class ExpressionPattern extends AbstractPattern { } } + @Override + public Pattern fork() { + return new ExpressionPattern(this.expression.clone()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java index 523f22541..e99383d06 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java @@ -7,6 +7,8 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + import static java.lang.Math.floorDiv; /** @@ -52,4 +54,10 @@ public class Linear2DBlockPattern extends AbstractPattern { return patternsArray[index].apply(extent, get, set); } + @Override + public Pattern fork() { + final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); + return new Linear2DBlockPattern(forked, this.xScale, this.zScale); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java index ea2e37588..e4d3822cc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java @@ -7,6 +7,8 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + import static java.lang.Math.floorDiv; /** @@ -56,4 +58,10 @@ public class Linear3DBlockPattern extends AbstractPattern { return patternsArray[index].apply(extent, get, set); } + @Override + public Pattern fork() { + final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); + return new Linear3DBlockPattern(forked, this.xScale, this.yScale, this.zScale); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java index 086cf3a31..1490bf37d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java @@ -1,5 +1,6 @@ package com.fastasyncworldedit.core.function.pattern; +import com.fastasyncworldedit.core.queue.Filter; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; @@ -7,6 +8,8 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + public class LinearBlockPattern extends AbstractPattern implements ResettablePattern { private final Pattern[] patternsArray; @@ -15,7 +18,7 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat /** * Create a new {@link Pattern} instance * - * @param patterns array of patterns to linearly choose from based on x/z coordinates + * @param patterns array of patterns to linearly choose from */ public LinearBlockPattern(Pattern[] patterns) { this.patternsArray = patterns; @@ -23,18 +26,14 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat @Override public BaseBlock applyBlock(BlockVector3 position) { - if (index == patternsArray.length) { - index = 0; - } - return patternsArray[index++].applyBlock(position); + index = (index + 1) % patternsArray.length; + return patternsArray[index].applyBlock(position); } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - if (index == patternsArray.length) { - index = 0; - } - return patternsArray[index++].apply(extent, get, set); + index = (index + 1) % patternsArray.length; + return patternsArray[index].apply(extent, get, set); } @Override @@ -42,4 +41,10 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat index = 0; } + @Override + public Pattern fork() { + final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); + return new LinearBlockPattern(forked); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java index 5d840d771..a5210feba 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java @@ -43,4 +43,9 @@ public class MaskedPattern extends AbstractPattern { return secondary.apply(extent, get, set); } + @Override + public Pattern fork() { + return new MaskedPattern(this.mask.copy(), this.primary.fork(), this.secondary.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java index d9fefb1bc..b4e9aac37 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java @@ -36,4 +36,9 @@ public class NoXPattern extends AbstractPattern { return pattern.apply(extent, mutable, set); } + @Override + public Pattern fork() { + return new NoXPattern(this.pattern.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java index 05d26f496..2fefaedfc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java @@ -36,4 +36,9 @@ public class NoYPattern extends AbstractPattern { return pattern.apply(extent, mutable, set); } + @Override + public Pattern fork() { + return new NoYPattern(this.pattern.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java index faebb59aa..8c100c5e3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.function.pattern; import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.queue.Filter; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; @@ -36,4 +37,9 @@ public class NoZPattern extends AbstractPattern { return pattern.apply(extent, mutable, set); } + @Override + public Pattern fork() { + return new NoZPattern(this.pattern.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java index 894f9d06a..9a5ca2ceb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java @@ -60,4 +60,16 @@ public class OffsetPattern extends AbstractPattern { return pattern.apply(extent, get, mutable); } + @Override + public BlockVector3 size() { + // Not exactly the "size" but offset should be taken into consideration in most + // places where the "size" matters + return BlockVector3.at(dx, dy, dz); + } + + @Override + public Pattern fork() { + return new OffsetPattern(this.pattern.fork(), this.dx, this.dy, this.dz, this.minY, this.maxY); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomFullClipboardPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomFullClipboardPattern.java index 52348780b..957cf2617 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomFullClipboardPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomFullClipboardPattern.java @@ -1,7 +1,9 @@ package com.fastasyncworldedit.core.function.pattern; +import com.fastasyncworldedit.core.math.MutableBlockVector3; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.pattern.AbstractPattern; import com.sk89q.worldedit.function.pattern.Pattern; @@ -9,6 +11,8 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.world.block.BaseBlock; @@ -23,6 +27,7 @@ public class RandomFullClipboardPattern extends AbstractPattern { private final boolean randomRotate; private final boolean randomFlip; private final Vector3 flipVector = Vector3.at(1, 0, 0).multiply(-2).add(1, 1, 1); + private final BlockVector3 size; /** * Create a new {@link Pattern} instance @@ -34,6 +39,12 @@ public class RandomFullClipboardPattern extends AbstractPattern { public RandomFullClipboardPattern(List clipboards, boolean randomRotate, boolean randomFlip) { checkNotNull(clipboards); this.clipboards = clipboards; + MutableBlockVector3 mut = new MutableBlockVector3(); + clipboards.stream().flatMap(c -> c.getClipboards().stream()).map(c -> { + Region region = c.getRegion(); + return region.getMaximumPoint().subtract(c.getOrigin().getMinimum(region.getMinimumPoint())); + }).forEach(mut::getMaximum); + this.size = mut.toImmutable(); this.randomRotate = randomRotate; this.randomFlip = randomFlip; } @@ -66,4 +77,9 @@ public class RandomFullClipboardPattern extends AbstractPattern { throw new IllegalStateException("Incorrect use. This pattern can only be applied to an extent!"); } + @Override + public BlockVector3 size() { + return size; + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java index 3eb5c3b77..c68bb24b1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java @@ -72,4 +72,14 @@ public class RandomOffsetPattern extends AbstractPattern { return pattern.apply(extent, get, mutable); } + @Override + public BlockVector3 size() { + return BlockVector3.at(dx2, dy2, dz2); + } + + @Override + public Pattern fork() { + return new RandomOffsetPattern(this.pattern.fork(), this.dx, this.dy, this.dz, this.minY, this.maxY); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java index cda875f04..541aaa494 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java @@ -63,4 +63,11 @@ public class RelativePattern extends AbstractPattern implements ResettablePatter origin = null; } + @Override + public Pattern fork() { + RelativePattern forked = new RelativePattern(this.pattern.fork(), this.minY, this.maxY); + forked.origin = this.origin; // maintain origin for forks + return forked; + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java index 12b64a497..54ecf6676 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java @@ -94,4 +94,9 @@ public class SolidRandomOffsetPattern extends AbstractPattern { return pattern.apply(extent, get, set); } + @Override + public Pattern fork() { + return new SolidRandomOffsetPattern(this.pattern.fork(), this.dx, this.dy, this.dz, this.minY, this.maxY); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java index 73327f94a..03e3126be 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java @@ -129,4 +129,14 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern { return !block.getBlockType().getMaterial().isMovementBlocker(); } + @Override + public BlockVector3 size() { + return BlockVector3.at(moves, moves, moves); + } + + @Override + public Pattern fork() { + return new SurfaceRandomOffsetPattern(this.pattern.fork(), this.moves, this.minY, this.maxY); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java index e904244de..67aeadec8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java @@ -78,6 +78,49 @@ public class BlockVectorSet extends AbstractCollection implements return localMap != null && localMap.contains(x & 2047, ((y + 128) & 511) - 128, z & 2047); } + @Override + public void setOffset(final int x, final int z) { + // Do nothing + } + + @Override + public void setOffset(final int x, final int y, final int z) { + // Do nothing + } + + @Override + public boolean containsRadius(final int x, final int y, final int z, final int radius) { + if (radius <= 0) { + return contains(x, y, z); + } + // Quick corners check + if (!contains(x - radius, y, z - radius)) { + return false; + } + if (!contains(x + radius, y, z + radius)) { + return false; + } + if (!contains(x - radius, y, z + radius)) { + return false; + } + if (!contains(x + radius, y, z - radius)) { + return false; + } + // Slow but if someone wants to think of an elegant way then feel free to add it + for (int xx = -radius; xx <= radius; xx++) { + int rx = x + xx; + for (int yy = -radius; yy <= radius; yy++) { + int ry = y + yy; + for (int zz = -radius; zz <= radius; zz++) { + if (contains(rx, ry, z + zz)) { + return true; + } + } + } + } + return false; + } + @Override public boolean contains(Object o) { if (o instanceof BlockVector3 v) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java index 8e6cdabe8..2ed3a2f63 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java @@ -100,14 +100,7 @@ public class LocalBlockVectorSet implements BlockVector3Set { return new LocalBlockVectorSet(offsetX, offsetY, offsetZ, set.clone()); } - /** - * If a radius is contained by the set - * - * @param x x radius center - * @param y y radius center - * @param z z radius center - * @return if radius is contained by the set - */ + @Override public boolean containsRadius(int x, int y, int z, int radius) { if (radius <= 0) { return contains(x, y, z); @@ -130,9 +123,11 @@ public class LocalBlockVectorSet implements BlockVector3Set { return false; } for (int xx = -radius; xx <= radius; xx++) { + int rx = x + xx; for (int yy = -radius; yy <= radius; yy++) { + int ry = y + yy; for (int zz = -radius; zz <= radius; zz++) { - if (contains(x + xx, y + yy, z + zz)) { + if (contains(rx, ry, z + zz)) { return true; } } @@ -141,27 +136,13 @@ public class LocalBlockVectorSet implements BlockVector3Set { return false; } - /** - * Set the offset applied to values when storing and reading to keep the values within -1024 to 1023. Uses default y offset - * of 128 to allow -64 -> 320 world height use. - * - * @param x x offset - * @param z z offset - */ + @Override public void setOffset(int x, int z) { this.offsetX = x; this.offsetZ = z; } - /** - * Set the offset applied to values when storing and reading to keep the x and z values within -1024 to 1023. Y values - * require keeping withing -256 and 255. - * - * @param x x offset - * @param y y offset - * @param z z offset - * @since 2.2.0 - */ + @Override public void setOffset(int x, int y, int z) { this.offsetX = x; this.offsetY = y; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java index baa20163f..6ebabae1d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java @@ -61,6 +61,22 @@ public class MutableBlockVector3 extends BlockVector3 { return z; } + @Override + public BlockVector3 getMinimum(BlockVector3 v2) { + this.x = Math.min(v2.getX(), x); + this.y = Math.min(v2.getY(), y); + this.z = Math.min(v2.getZ(), z); + return this; + } + + @Override + public BlockVector3 getMaximum(BlockVector3 v2) { + this.x = Math.max(v2.getX(), x); + this.y = Math.max(v2.getY(), y); + this.z = Math.max(v2.getZ(), z); + return this; + } + @Override public MutableBlockVector3 mutX(double x) { this.x = (int) x; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java index e7038deaa..6ae147765 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java @@ -51,11 +51,10 @@ public class ExtentTraverser { return last; } - @SuppressWarnings("unchecked") @Nullable - public U findAndGet(Class clazz) { - ExtentTraverser traverser = find(clazz); - return (traverser != null) ? (U) traverser.get() : null; + public U findAndGet(Class clazz) { + ExtentTraverser traverser = find(clazz); + return (traverser != null) ? traverser.get() : null; } @SuppressWarnings("unchecked") diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index cbe9c6897..41c4e5704 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -40,6 +40,7 @@ import javax.annotation.Nullable; import javax.imageio.ImageIO; import javax.imageio.ImageReadParam; import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; @@ -58,6 +59,9 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; @@ -94,6 +98,10 @@ import static java.lang.System.arraycopy; public class MainUtil { private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final String CURL_USER_AGENT = "curl/8.1.1"; + private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder() + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); public static List filter(String prefix, List suggestions) { if (prefix.isEmpty()) { @@ -523,25 +531,52 @@ public class MainUtil { } public static BufferedImage readImage(InputStream stream) throws IOException { - Iterator iter = ImageIO.getImageReaders(stream); + final ImageInputStream imageStream = ImageIO.createImageInputStream(stream); + if (imageStream == null) { + throw new IOException("Can't find suitable ImageInputStream"); + } + Iterator iter = ImageIO.getImageReaders(imageStream); if (!iter.hasNext()) { throw new IOException("Could not get image reader from stream."); } ImageReader reader = iter.next(); ImageReadParam param = reader.getDefaultReadParam(); - reader.setInput(stream, true, true); + reader.setInput(imageStream, true, true); BufferedImage bi; try { bi = reader.read(0, param); } finally { reader.dispose(); stream.close(); + imageStream.close(); } return MainUtil.toRGB(bi); } public static BufferedImage readImage(URL url) throws IOException { - return readImage(url.openStream()); + try { + final URI uri = url.toURI(); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + + if (uri.getHost().equalsIgnoreCase("i.imgur.com")) { + requestBuilder = requestBuilder.setHeader("User-Agent", CURL_USER_AGENT); + } + + final HttpResponse response = HTTP_CLIENT.send( + requestBuilder.build(), + HttpResponse.BodyHandlers.ofInputStream() + ); + try (final InputStream body = response.body()) { + if (response.statusCode() > 299) { + throw new IOException("Expected 2xx as response code, but received " + response.statusCode()); + } + return readImage(body); + } + } catch (InterruptedException e) { + throw new IOException("request was interrupted", e); + } catch (URISyntaxException e) { + throw new IOException("failed to parse url to uri reference", e); + } } public static BufferedImage readImage(File file) throws IOException { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java index 881aaf9f3..83a639ead 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java @@ -9,29 +9,80 @@ import java.util.Set; public interface BlockVector3Set extends Set { + /** + * Get the appropriate {@link BlockVector3Set} implementation for the given region. Either {@link LocalBlockVectorSet} or + * {@link BlockVectorSet}. Sets the offset if using {@link LocalBlockVectorSet}. + * + * @param region Region to get for + * @return Appropriate {@link BlockVector3Set} implementation + */ static BlockVector3Set getAppropriateVectorSet(Region region) { BlockVector3 max = region.getMaximumPoint(); BlockVector3 min = region.getMinimumPoint(); - BlockVector3 size = region.getDimensions(); + BlockVector3Set set = getAppropriateVectorSet(region.getDimensions()); + // Set default offset as many operations utilising a region are likely to start in a corner, this initialising the + // LocalBlockVectorSet poorly + // This needs to be ceiling as LocalBlockVector extends 1 block further "negative" + int offsetX = (int) Math.ceil((min.getX() + max.getX()) / 2d); + int offsetZ = (int) Math.ceil((min.getZ() + max.getZ()) / 2d); + int offsetY; + if (region.getMinimumY() < -128 || region.getMaximumY() > 320) { + offsetY = (min.getY() + max.getY()) / 2; + } else { + offsetY = 128; + } + set.setOffset(offsetX, offsetY, offsetZ); + return set; + } + + /** + * Get the appropriate {@link BlockVector3Set} implementation for the given dimensions. Either {@link LocalBlockVectorSet} or + * {@link BlockVectorSet}. The offset should be manually set. + * + * @param size Dimensions to get for + * @return Appropriate {@link BlockVector3Set} implementation + */ + static BlockVector3Set getAppropriateVectorSet(BlockVector3 size) { if (size.getBlockX() > 2048 || size.getBlockZ() > 2048 || size.getBlockY() > 512) { return new BlockVectorSet(); } else { - // Set default offset as many operations utilising a region are likely to start in a corner, this initialising the - // LocalBlockVectorSet poorly - // This needs to be ceiling as LocalBlockVector extends 1 block further "negative" - int offsetX = (int) Math.ceil((min.getX() + max.getX()) / 2d); - int offsetZ = (int) Math.ceil((min.getZ() + max.getZ()) / 2d); - int offsetY; - if (region.getMinimumY() < -128 || region.getMaximumY() > 320) { - offsetY = (min.getY() + max.getY()) / 2; - } else { - offsetY = 128; - } - return new LocalBlockVectorSet(offsetX, offsetY, offsetZ); + return new LocalBlockVectorSet(); } } boolean add(int x, int y, int z); boolean contains(int x, int y, int z); + /** + * Set the offset applied to values when storing and reading to keep the values within -1024 to 1023. Uses default y offset + * of 128 to allow -64 -> 320 world height use. + * + * @param x x offset + * @param z z offset + * @since TODO + */ + void setOffset(int x, int z); + + /** + * Set the offset applied to values when storing and reading to keep the x and z values within -1024 to 1023. Y values + * require keeping withing -256 and 255. + * + * @param x x offset + * @param y y offset + * @param z z offset + * @since TODO + */ + void setOffset(int x, int y, int z); + + /** + * If a radius is contained by the set + * + * @param x x radius center + * @param y y radius center + * @param z z radius center + * @return if radius is contained by the set + * @since TODO + */ + boolean containsRadius(int x, int y, int z, int radius); + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java index f569acd00..ca2bfd965 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java @@ -235,4 +235,11 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat }; } + //FAWE - stateful pattern + @Override + public Pattern fork() { + return new ForgetfulExtentBuffer(extent, mask.copy()); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java index 49e7f5472..863cf1e25 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java @@ -25,6 +25,8 @@ import com.sk89q.worldedit.extent.buffer.ExtentBuffer; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + import static com.google.common.base.Preconditions.checkArgument; /** @@ -64,4 +66,12 @@ public class ExtentBufferedCompositePattern extends AbstractExtentPattern { return lastBlock; } + //FAWE - stateful pattern + @Override + public Pattern fork() { + final Pattern[] forkedPatterns = Arrays.stream(patterns).map(Pattern::fork).toArray(Pattern[]::new); + return new ExtentBufferedCompositePattern(getExtent(), forkedPatterns); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java index 801b07a65..e44a1c19d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.block.BaseBlock; /** @@ -59,6 +60,11 @@ public interface Pattern extends Filter { apply(block, block, block); } + @Override + default Pattern fork() { // covariant return type + return this; + } + //FAWE end /** @@ -69,4 +75,14 @@ public interface Pattern extends Filter { */ BaseBlock applyBlock(BlockVector3 position); + /** + * Get the likely maximum size of the volume this pattern will affect + * + * @return Pattern size + * @since TODO + */ + default BlockVector3 size() { + return BlockVector3.ONE; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java index 1d2df7223..c45629e5f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java @@ -67,6 +67,13 @@ public class RandomPattern extends AbstractPattern { this.collection = RandomCollection.of(weights, random); this.patterns = parent.patterns; } + + private RandomPattern(SimpleRandom random, Map weights) { + this.random = random; + this.weights = weights; + this.collection = RandomCollection.of(weights, random); + this.patterns = new LinkedHashSet<>(weights.keySet()); + } //FAWE end /** @@ -107,6 +114,14 @@ public class RandomPattern extends AbstractPattern { public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(extent, get, set); } + + @Override + public Pattern fork() { + final LinkedHashMap newWeights = new LinkedHashMap<>(); + this.weights.forEach((p, w) -> newWeights.put(p.fork(), w)); + return new RandomPattern(this.random, newWeights); + } + //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java index 3d834f76b..b328e78ea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java @@ -29,13 +29,16 @@ import com.sk89q.worldedit.world.block.BlockType; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; import static com.sk89q.worldedit.blocks.Blocks.resolveProperties; public class StateApplyingPattern extends AbstractExtentPattern { private final Map states; - private final Map, Object>> cache = Maps.newHashMap(); + //FAWE - avoid race conditions + private final Map, Object>> cache = new ConcurrentHashMap<>(); + //FAWE end public StateApplyingPattern(Extent extent, Map statesToSet) { super(extent); 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 4b87ebcc6..2284b9733 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 @@ -85,7 +85,7 @@ public class WorldEditExpressionEnvironment implements ExpressionEnvironment { @SuppressWarnings("deprecation") @Override public int getBlockDataRel(double x, double y, double z) { - return extent.getBlock(toWorld(x, y, z)).getBlockType().getLegacyCombinedId() & 0xF; + return extent.getBlock(toWorldRel(x, y, z).toBlockPoint()).getBlockType().getLegacyCombinedId() & 0xF; } //FAWE start