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/gradle/libs.versions.toml b/gradle/libs.versions.toml index a6acb6c2e..85d7a18c8 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.23" plotsquared = "7.3.6" # Third party 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 02f5a3c53..088dd6f41 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-20240106.182028-62") + the().paperDevBundle("1.20.4-R0.1-20240323.213332-142") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java index edbe268fe..74b1c035c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java @@ -2,18 +2,15 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; import com.google.common.base.Suppliers; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.util.ReflectionUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.world.registry.BlockMaterial; import net.minecraft.core.BlockPos; import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.LiquidBlock; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.material.PushReaction; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; @@ -21,7 +18,6 @@ public class PaperweightBlockMaterial implements BlockMaterial { private final Block block; private final BlockState blockState; - private final boolean isTranslucent; private final CraftBlockData craftBlockData; private final org.bukkit.Material craftMaterial; private final int opacity; @@ -36,11 +32,6 @@ public class PaperweightBlockMaterial implements BlockMaterial { this.blockState = blockState; this.craftBlockData = CraftBlockData.fromData(blockState); this.craftMaterial = craftBlockData.getMaterial(); - BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, - Refraction.pickName("properties", "aP")); - this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, - Refraction.pickName("canOcclude", "n") - ); opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( BlockPos.ZERO, @@ -75,7 +66,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isOpaque() { - return blockState.isOpaque(); + return blockState.canOcclude(); } @Override @@ -85,14 +76,13 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isLiquid() { - // TODO: Better check ? - return block instanceof LiquidBlock; + return !blockState.getFluidState().is(Fluids.EMPTY); } @Override public boolean isSolid() { - // TODO: Replace - return blockState.isSolid(); + // No access to world -> EmptyBlockGetter + return blockState.isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); } @Override @@ -158,7 +148,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isTranslucent() { - return isTranslucent; + return !blockState.canOcclude(); } @Override diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index a9ba45afe..1598cb547 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -327,12 +327,12 @@ public class BukkitWorld extends AbstractWorld { treeTypeMapping.put(TreeGenerator.TreeType.RANDOM_MUSHROOM, TreeType.BROWN_MUSHROOM); for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) { if (treeTypeMapping.get(type) == null) { - LOGGER.error("No TreeType mapping for TreeGenerator.TreeType." + type); //FAWE start + LOGGER.info("No TreeType mapping for TreeGenerator.TreeType." + type); LOGGER.info("The above message is displayed because your FAWE version is newer than {}" + " and contains features of future minecraft versions which do not exist in {} hence the tree type" + - "{} is not available. This is not an error. This version will work on your version of Minecraft." + - "This is an informative message only.", Bukkit.getVersion(), Bukkit.getVersion(), type); + " {} is not available. This is not an error. This version of FAWE will work on your version of " + + " Minecraft. This is an informative message only.", Bukkit.getVersion(), Bukkit.getVersion(), type); //FAWE end } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java index fea4884f1..2c6ea5ec0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java @@ -53,7 +53,7 @@ public class HeightBrush implements Brush { try { heightMap = ScalableHeightMap.fromPNG(stream); } catch (IOException e) { - throw new FaweException(Caption.of("fawe.worldedit.brush.brush.height.invalid")); + throw new FaweException(Caption.of("fawe.worldedit.brush.brush.height.invalid", e.getMessage())); } } else if (clipboard != null) { heightMap = ScalableHeightMap.fromClipboard(clipboard, minY, maxY); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java index 5a310f60a..7da0b2377 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java @@ -2,7 +2,7 @@ package com.fastasyncworldedit.core.extension.factory.parser.pattern; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extension.factory.parser.RichParser; -import com.fastasyncworldedit.core.function.pattern.Linear2DBlockPattern; +import com.fastasyncworldedit.core.math.random.Linear2DRandom; import com.google.common.base.Preconditions; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; @@ -14,7 +14,6 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nonnull; -import java.util.Set; import java.util.stream.Stream; public class Linear2DPatternParser extends RichParser { @@ -59,9 +58,8 @@ public class Linear2DPatternParser extends RichParser { zScale = Integer.parseInt(arguments[2]); Preconditions.checkArgument(zScale != 0); } - if (inner instanceof RandomPattern) { - Set patterns = ((RandomPattern) inner).getPatterns(); - return new Linear2DBlockPattern(patterns.toArray(new Pattern[0]), xScale, zScale); + if (inner instanceof RandomPattern rp) { + return new RandomPattern(new Linear2DRandom(xScale, zScale), rp); } throw new InputParseException(TextComponent.of("Pattern " + inner.getClass().getSimpleName() + " cannot be used with " + getPrefix())); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java index ef45e8faa..cd3a7d8db 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java @@ -2,7 +2,7 @@ package com.fastasyncworldedit.core.extension.factory.parser.pattern; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extension.factory.parser.RichParser; -import com.fastasyncworldedit.core.function.pattern.Linear3DBlockPattern; +import com.fastasyncworldedit.core.math.random.Linear3DRandom; import com.google.common.base.Preconditions; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; @@ -14,7 +14,6 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nonnull; -import java.util.Set; import java.util.stream.Stream; public class Linear3DPatternParser extends RichParser { @@ -64,9 +63,8 @@ public class Linear3DPatternParser extends RichParser { zScale = Integer.parseInt(arguments[3]); Preconditions.checkArgument(zScale != 0); } - if (inner instanceof RandomPattern) { - Set patterns = ((RandomPattern) inner).getPatterns(); - return new Linear3DBlockPattern(patterns.toArray(new Pattern[0]), xScale, yScale, zScale); + if (inner instanceof RandomPattern rp) { + return new RandomPattern(new Linear3DRandom(xScale, yScale, zScale), rp); } throw new InputParseException(TextComponent.of("Pattern " + inner.getClass().getSimpleName() + " cannot be used with " + getPrefix())); 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 7c923c4d4..523f22541 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 @@ -9,6 +9,11 @@ import com.sk89q.worldedit.world.block.BaseBlock; import static java.lang.Math.floorDiv; +/** + * @deprecated replaced by {@link com.sk89q.worldedit.function.pattern.RandomPattern} + * combined with {@link com.fastasyncworldedit.core.math.random.Linear2DRandom}. + */ +@Deprecated(forRemoval = true, since = "TODO") public class Linear2DBlockPattern extends AbstractPattern { private final Pattern[] patternsArray; 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 04028244d..ea2e37588 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 @@ -9,6 +9,11 @@ import com.sk89q.worldedit.world.block.BaseBlock; import static java.lang.Math.floorDiv; +/** + * @deprecated replaced by {@link com.sk89q.worldedit.function.pattern.RandomPattern} + * combined with {@link com.fastasyncworldedit.core.math.random.Linear3DRandom}. + */ +@Deprecated(forRemoval = true, since = "TODO") public class Linear3DBlockPattern extends AbstractPattern { private final Pattern[] patternsArray; 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..0b6ef1be9 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,20 @@ 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 + public Filter fork() { + final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); + return new LinearBlockPattern(forked); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java new file mode 100644 index 000000000..4f039031e --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java @@ -0,0 +1,50 @@ +package com.fastasyncworldedit.core.math.random; + +import static com.fastasyncworldedit.core.math.random.Linear3DRandom.doubleDiv; +import static java.lang.Math.floorDiv; + +/** + * A {@link SimpleRandom} that deterministically maps coordinates + * to values. + * @since TODO + */ +public class Linear2DRandom implements SimpleRandom { + private final int xScale; + private final int zScale; + + /** + * Creates a new {@link Linear2DRandom} instance + * + * @param xScale the scale applied to the x component of a coordinate + * @param zScale the scale applied to the z component of a coordinate + */ + public Linear2DRandom(final int xScale, final int zScale) { + this.xScale = xScale; + this.zScale = zScale; + } + + @Override + public double nextDouble(final int x, final int y, final int z) { + return nextDouble(x, y, z, 1d); + } + + @Override + public double nextDouble(final int x, final int y, final int z, double bound) { + double index = (doubleDiv(x, this.xScale) + doubleDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + + } + + @Override + public int nextInt(final int x, final int y, final int z, final int bound) { + int index = (floorDiv(x, this.xScale) + floorDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java new file mode 100644 index 000000000..87f350fe4 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java @@ -0,0 +1,58 @@ +package com.fastasyncworldedit.core.math.random; + +import static java.lang.Math.floorDiv; + +/** + * A {@link SimpleRandom} that deterministically maps coordinates + * to values. + * @since TODO + */ +public class Linear3DRandom implements SimpleRandom { + + private final int xScale; + private final int yScale; + private final int zScale; + + /** + * Creates a new {@link Linear3DRandom} instance + * + * @param xScale the scale applied to the x component of a coordinate + * @param yScale the scale applied to the y component of a coordinate + * @param zScale the scale applied to the z component of a coordinate + */ + public Linear3DRandom(final int xScale, final int yScale, final int zScale) { + this.xScale = xScale; + this.yScale = yScale; + this.zScale = zScale; + } + + @Override + public double nextDouble(final int x, final int y, final int z) { + return nextDouble(x, y, z, 1d); + } + + @Override + public double nextDouble(final int x, final int y, final int z, double bound) { + double index = (doubleDiv(x, this.xScale) + doubleDiv(y, this.yScale) + doubleDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + } + + // used to avoid explicit conversion at call site + static double doubleDiv(double dividend, double divisor) { + // add a minimal value to avoid too many integral values hitting the exact weight of an entry in SimpleRandomCollection + return Math.nextUp(dividend) / divisor; + } + + @Override + public int nextInt(final int x, final int y, final int z, final int bound) { + int index = (floorDiv(x, this.xScale) + floorDiv(y, this.yScale) + floorDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java index e38214936..8b22b66a2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java @@ -13,6 +13,20 @@ public interface SimpleRandom { */ double nextDouble(int x, int y, int z); + /** + * Generate a random double from three integer components. + * The generated value is between 0 (inclusive) and {@code bound} (exclusive). + * + * @param x the first component + * @param y the second component + * @param z the third component + * @param bound upper bound (exclusive) + * @return a double between 0 (inclusive) and {@code bound} (exclusive) + */ + default double nextDouble(int x, int y, int z, double bound) { + return nextDouble(x, y, z) * bound; + } + /** * Generate a random integer from three integer components. * The generated value is between 0 (inclusive) and 1 (exclusive) @@ -24,8 +38,8 @@ public interface SimpleRandom { * @return a random integer between 0 (inclusive) and {@code bound} (exclusive) */ default int nextInt(int x, int y, int z, int bound) { - double val = nextDouble(x, y, z); - return (int) (val * bound); + double val = nextDouble(x, y, z, bound); + return (int) val; } } 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 6150ae2e3..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((Class) clazz); - return (traverser != null) ? (U) traverser.get() : null; + 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 8122a840c..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 @@ -38,6 +38,9 @@ import org.apache.logging.log4j.Logger; import javax.annotation.Nonnull; 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; @@ -56,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; @@ -70,6 +76,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -91,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()) { @@ -519,12 +530,53 @@ public class MainUtil { return destFile; } - public static BufferedImage readImage(InputStream in) throws IOException { - return MainUtil.toRGB(ImageIO.read(in)); + public static BufferedImage readImage(InputStream stream) throws IOException { + 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(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/SimpleRandomCollection.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/SimpleRandomCollection.java index dc2107559..5b7dca98f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/SimpleRandomCollection.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/SimpleRandomCollection.java @@ -36,7 +36,7 @@ public class SimpleRandomCollection extends RandomCollection { @Override public E next(int x, int y, int z) { - return map.ceilingEntry(getRandom().nextDouble(x, y, z) * this.total).getValue(); + return map.ceilingEntry(getRandom().nextDouble(x, y, z, this.total)).getValue(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/ItemTypeAdapter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/ItemTypeAdapter.java similarity index 94% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/ItemTypeAdapter.java rename to worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/ItemTypeAdapter.java index 5f8d6d9a2..fe684fb8c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/ItemTypeAdapter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/ItemTypeAdapter.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.util.gson; +package com.fastasyncworldedit.core.util.gson; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/RegionSelectorAdapter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/RegionSelectorAdapter.java new file mode 100644 index 000000000..d817185ee --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/RegionSelectorAdapter.java @@ -0,0 +1,33 @@ +package com.fastasyncworldedit.core.util.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelectorType; + +import java.lang.reflect.Type; + +public class RegionSelectorAdapter implements JsonDeserializer, JsonSerializer { + + @Override + public RegionSelector deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { + RegionSelectorType regionType = RegionSelectorType.valueOf(json.getAsString()); + return regionType.createSelector(); + } + + @Override + public JsonElement serialize(RegionSelector selector, Type type, JsonSerializationContext context) { + RegionSelectorType regionType = RegionSelectorType.getForSelector(selector); + // Cannot nicely deserialize Fuzzy region type + if (regionType == null || regionType == RegionSelectorType.FUZZY) { + return null; + } + return new JsonPrimitive(regionType.toString()); + } + +} 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 a00b26702..5a5fa654e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -125,7 +125,9 @@ public class LocalSession implements TextureHolder { private transient int cuiVersion = CUI_VERSION_UNINITIALIZED; // Session related - private transient RegionSelector selector = new CuboidRegionSelector(); + //FAWE start - allow saving to session store + private RegionSelector selector = new CuboidRegionSelector(); + //FAWE end private transient boolean placeAtPos1 = false; //FAWE start private final transient List history = Collections.synchronizedList(new LinkedList<>() { @@ -771,6 +773,7 @@ public class LocalSession implements TextureHolder { checkNotNull(selector); selector.setWorld(world); this.selector = selector; + setDirty(); if (hasWorldOverride() && !world.equals(getWorldOverride())) { setWorldOverride(null); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 64e3c8a81..a643742d2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -755,13 +755,7 @@ public class SelectionCommands { } if (setDefaultSelector) { - RegionSelectorType found = null; - for (RegionSelectorType type : RegionSelectorType.values()) { - if (type.getSelectorClass() == newSelector.getClass()) { - found = type; - break; - } - } + RegionSelectorType found = RegionSelectorType.getForSelector(newSelector); if (found != null) { session.setDefaultRegionSelector(found); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java index 0e70a18a6..969216896 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java @@ -64,6 +64,7 @@ import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; +import javax.annotation.Nonnull; import java.util.Arrays; import java.util.HashMap; import java.util.Locale; @@ -337,9 +338,10 @@ public class DefaultBlockParser extends InputParser { return SuggestionHelper.getBlockPropertySuggestions(blockType, props); } + @Nonnull private BaseBlock parseLogic(String input, ParserContext context) throws InputParseException { //FAWE start - String[] blockAndExtraData = input.trim().split("\\|"); + String[] blockAndExtraData = input.trim().split("(?, Object> blockStates = new HashMap<>(); //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java index 61e46aeab..5c8655893 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java @@ -19,8 +19,14 @@ package com.sk89q.worldedit.regions.selector; +import com.fastasyncworldedit.core.regions.selector.FuzzyRegionSelector; +import com.fastasyncworldedit.core.regions.selector.PolyhedralRegionSelector; import com.sk89q.worldedit.regions.RegionSelector; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + /** * An enum of default region selector types. */ @@ -32,7 +38,21 @@ public enum RegionSelectorType { SPHERE(SphereRegionSelector.class), ELLIPSOID(EllipsoidRegionSelector.class), POLYGON(Polygonal2DRegionSelector.class), - CONVEX_POLYHEDRON(ConvexPolyhedralRegionSelector.class); + CONVEX_POLYHEDRON(ConvexPolyhedralRegionSelector.class), + //FAWE start + POLYHEDRAL(PolyhedralRegionSelector.class), + FUZZY(FuzzyRegionSelector.class); + //FAWE end + + //FAWE start + private static final Map, RegionSelectorType> VALUE_MAP = new HashMap<>(); + + static { + for (RegionSelectorType type : values()) { + VALUE_MAP.put(type.getSelectorClass(), type); + } + } + //FAWE end private final Class selectorClass; @@ -40,6 +60,19 @@ public enum RegionSelectorType { this.selectorClass = selectorClass; } + //FAWE start + /** + * Get a {@link RegionSelectorType} for the given {@link RegionSelector} + * + * @param selector Region selector to get type enum for + * @since TODO + */ + @Nullable + public static RegionSelectorType getForSelector(RegionSelector selector) { + return VALUE_MAP.get(selector.getClass()); + } + //FAWE end + /** * Get the selector class. * 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 diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java index d31750e11..e5d05ee6d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java @@ -19,12 +19,14 @@ package com.sk89q.worldedit.util.gson; +import com.fastasyncworldedit.core.util.gson.ItemTypeAdapter; +import com.fastasyncworldedit.core.util.gson.RegionSelectorAdapter; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.world.item.ItemType; -import com.sk89q.worldedit.world.item.ItemTypes; /** * Utility methods for Google's GSON library. @@ -43,7 +45,10 @@ public final class GsonUtil { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); gsonBuilder.registerTypeAdapter(BlockVector3.class, new BlockVectorAdapter()); + //FAWE start + gsonBuilder.registerTypeAdapter(RegionSelector.class, new RegionSelectorAdapter()); gsonBuilder.registerTypeAdapter(ItemType.class, new ItemTypeAdapter()); + //FAWE end return gsonBuilder; }