From d4d98708f9c91c0c8ebd818c370ea776e6bd9b93 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Mon, 16 Aug 2021 10:03:06 +0100 Subject: [PATCH] Re-implement richer mask and transform parsing (#1223) Co-authored-by: dordsor21 Co-authored-by: Hannes Greule --- .../core/command/FaweParser.java | 114 -- .../core/command/MaskCommands.java | 132 --- .../core/command/PatternCommands.java | 356 ------- .../core/command/TransformCommands.java | 105 -- .../core/command/tool/brush/ImageBrush.java | 12 +- .../factory/DefaultTransformParser.java | 136 --- .../extension/factory/TransformFactory.java | 144 +++ .../factory/parser/AliasedParser.java | 14 + .../extension/factory/parser/FaweParser.java | 134 +++ .../extension/factory/parser/RichParser.java | 29 +- .../parser/mask/DefaultMaskParser.java | 189 ---- .../factory/parser/mask/RichMaskParser.java | 241 +++++ .../pattern/AngleColorPatternParser.java | 47 + .../pattern/AverageColorPatternParser.java | 53 + .../parser/pattern/BiomePatternParser.java | 2 +- .../pattern/BufferedPattern2DParser.java | 46 + .../parser/pattern/ColorPatternParser.java | 53 + .../parser/pattern/DarkenPatternParser.java | 36 + .../parser/pattern/DefaultPatternParser.java | 167 --- .../pattern/DesaturatePatternParser.java | 46 + .../parser/pattern/ExistingPatternParser.java | 5 + .../pattern/ExpressionPatternParser.java | 53 + .../parser/pattern/LightenPatternParser.java | 36 + .../parser/pattern/LinearPatternParser.java | 64 ++ .../parser/pattern/MaskedPatternParser.java | 54 + .../parser/pattern/NoXPatternParser.java | 46 + .../parser/pattern/NoYPatternParser.java | 46 + .../parser/pattern/NoZPatternParser.java | 46 + .../parser/pattern/OffsetPatternParser.java | 67 ++ .../RandomFullClipboardPatternParser.java | 93 ++ .../pattern/RandomOffsetPatternParser.java | 65 ++ .../parser/pattern/RandomPatternParser.java | 5 + .../parser/pattern/RelativePatternParser.java | 48 + .../parser/pattern/RichPatternParser.java | 211 ++++ .../parser/pattern/SaturatePatternParser.java | 51 + .../parser/pattern/SimplexPatternParser.java | 5 + .../SolidRandomOffsetPatternParser.java | 65 ++ .../SurfaceRandomOffsetPatternParser.java | 54 + .../transform/Linear3DTransformParser.java | 45 + .../transform/LinearTransformParser.java | 45 + .../transform/OffsetTransformParser.java | 55 + .../transform/PatternTransformParser.java | 47 + .../transform/RandomTransformParser.java | 60 ++ .../parser/transform/RichTransformParser.java | 170 +++ .../transform/RotateTransformParser.java | 57 + .../transform/ScaleTransformParser.java | 57 + .../transform/SpreadTransformParser.java | 49 + .../platform/binding/PrimitiveBindings.java | 26 - .../core/extent/FaweRegionExtent.java | 1 + .../core/extent/NullExtent.java | 30 +- .../core/extent/OffsetExtent.java | 49 - .../core/extent/ResettableExtent.java | 3 +- .../clipboard/io/schematic/PNGWriter.java | 11 +- .../extent/transform/Linear3DTransform.java | 6 + .../extent/transform/LinearTransform.java | 8 +- .../core/extent/transform/MultiTransform.java | 15 + .../extent/transform/OffsetTransform.java | 77 ++ .../extent/transform/PatternTransform.java | 7 +- .../RandomOffsetTransform.java | 39 +- .../extent/transform/RandomTransform.java | 6 + .../core/extent/transform/ScaleTransform.java | 126 ++- .../extent/transform/SelectTransform.java | 5 + .../core/function/mask/BlockMaskBuilder.java | 4 + .../function/pattern/AngleColorPattern.java | 29 +- ...ataAnglePattern.java => AnglePattern.java} | 33 +- .../function/pattern/AverageColorPattern.java | 39 +- .../pattern/BiomeApplyingPattern.java | 7 + .../function/pattern/BufferedPattern.java | 10 +- .../function/pattern/BufferedPattern2D.java | 6 + .../core/function/pattern/DataPattern.java | 47 - .../function/pattern/DesaturatePattern.java | 31 +- .../function/pattern/ExistingPattern.java | 6 + .../function/pattern/IdDataMaskPattern.java | 28 - .../core/function/pattern/IdPattern.java | 27 - .../pattern/Linear2DBlockPattern.java | 7 + .../pattern/Linear3DBlockPattern.java | 8 + .../function/pattern/LinearBlockPattern.java | 5 + .../core/function/pattern/MaskedPattern.java | 7 + .../core/function/pattern/NoXPattern.java | 5 + .../core/function/pattern/NoYPattern.java | 5 + .../core/function/pattern/NoZPattern.java | 8 +- .../core/function/pattern/OffsetPattern.java | 19 +- .../function/pattern/PropertyPattern.java | 259 ----- .../pattern/RandomFullClipboardPattern.java | 14 +- .../function/pattern/RandomOffsetPattern.java | 19 +- .../function/pattern/RelativePattern.java | 18 +- .../function/pattern/SaturatePattern.java | 45 +- .../core/function/pattern/ShadePattern.java | 31 +- .../pattern/SolidRandomOffsetPattern.java | 35 +- .../pattern/SurfaceRandomOffsetPattern.java | 18 +- .../core/util/DelegateTextureUtil.java | 46 +- .../core/util/TextureUtil.java | 986 ++++++++++-------- .../main/java/com/sk89q/util/StringUtil.java | 4 +- .../java/com/sk89q/worldedit/WorldEdit.java | 13 + .../worldedit/command/GeneralCommands.java | 121 +-- .../worldedit/command/ToolUtilCommands.java | 57 +- .../command/argument/FactoryConverter.java | 40 +- .../command/util/SuggestionHelper.java | 21 + .../extension/factory/MaskFactory.java | 75 +- .../extension/factory/PatternFactory.java | 153 ++- .../factory/parser/DefaultBlockParser.java | 16 +- .../pattern/BlockCategoryPatternParser.java | 14 +- .../pattern/RandomStatePatternParser.java | 14 +- .../TypeOrStateApplyingPatternParser.java | 15 +- .../platform/PlatformCommandManager.java | 4 +- .../com/sk89q/worldedit/extent/Extent.java | 22 + .../internal/registry/AbstractFactory.java | 27 + .../internal/registry/SimpleInputParser.java | 13 +- .../src/main/resources/lang/strings.json | 7 + 109 files changed, 4068 insertions(+), 2414 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/command/FaweParser.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/command/MaskCommands.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/command/PatternCommands.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/command/TransformCommands.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/DefaultTransformParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/TransformFactory.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/AliasedParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/DefaultMaskParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AngleColorPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AverageColorPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ColorPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DarkenPatternParser.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DefaultPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DesaturatePatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ExpressionPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LightenPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LinearPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/MaskedPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoXPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoYPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoZPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/OffsetPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomFullClipboardPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomOffsetPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RelativePatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RichPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SaturatePatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SolidRandomOffsetPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SurfaceRandomOffsetPatternParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/Linear3DTransformParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/LinearTransformParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/OffsetTransformParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/PatternTransformParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RandomTransformParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RichTransformParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RotateTransformParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/ScaleTransformParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/SpreadTransformParser.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/OffsetExtent.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/OffsetTransform.java rename worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/{ => transform}/RandomOffsetTransform.java (56%) rename worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/{DataAnglePattern.java => AnglePattern.java} (68%) delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/DataPattern.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/IdDataMaskPattern.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/IdPattern.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/PropertyPattern.java diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/FaweParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/FaweParser.java deleted file mode 100644 index 324885e03..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/FaweParser.java +++ /dev/null @@ -1,114 +0,0 @@ -// TODO: Ping @MattBDev to reimplement 2020-02-04 -//package com.boydti.fawe.command; -// -//import com.boydti.fawe.util.StringMan; -//import com.sk89q.worldedit.WorldEdit; -//import com.sk89q.worldedit.extension.input.InputParseException; -//import com.sk89q.worldedit.extension.input.ParserContext; -//import com.sk89q.worldedit.extension.platform.PlatformCommandManager; -//import com.sk89q.worldedit.internal.registry.InputParser; -//import org.enginehub.piston.inject.InjectedValueAccess; -// -//import java.util.*; -// -//public abstract class FaweParser extends InputParser { -// -// private final String prefix; -// -// protected FaweParser(WorldEdit worldEdit, String prefix) { -// super(worldEdit); -// this.prefix = prefix; -// } -// -// public PlatformCommandManager getPlatform() { -// return PlatformCommandManager.getInstance(); -// } -// -// public T parse(String input, ParserContext context) { -// input = prefix + " " + input; -// InjectedValueAccess injected = context.getInjected(); -// if (injected != null) { -// return getPlatform().parseCommand(input, injected); -// } else { -// return getPlatform().parseCommand(input, context.getActor()); -// } -// } -// -// public T catchSuggestion(String currentInput, String nextInput, ParserContext context) throws InputParseException { -// try { -// return parseFromInput(nextInput, context); -// } catch (SuggestInputParseException e) { -// e.prepend(currentInput.substring(0, currentInput.length() - nextInput.length())); -// throw e; -// } -// } -// -// protected static class ParseEntry { -// public boolean and; -// public String input; -// public String full; -// -// public ParseEntry(String full, String input, boolean type) { -// this.full = full; -// this.input = input; -// this.and = type; -// } -// -// @Override -// public String toString() { -// return input + " | " + and; -// } -// } -// -// public static List>> parse(String toParse) throws InputParseException { -// List>> keys = new ArrayList<>(); -// List inputs = new ArrayList<>(); -// List and = new ArrayList<>(); -// int last = 0; -// outer: -// for (int i = 0; i < toParse.length(); i++) { -// char c = toParse.charAt(i); -// switch (c) { -// case ',': -// case '&': -// String result = toParse.substring(last, i); -// if (!result.isEmpty()) { -// inputs.add(result); -// and.add(c == '&'); -// } else { -// throw new InputParseException("Invalid dangling character " + c); -// } -// last = i + 1; -// continue outer; -// default: -// if (c == '[' && StringMan.getMatchingBracket(c) != c) { -// int next = StringMan.findMatchingBracket(toParse, i); -// if (next != -1) { -// i = next; -// } else { -// toParse += "]"; -// i = toParse.length(); -// } -// continue outer; -// } -// } -// } -// inputs.add(toParse.substring(last)); -// for (int i = 0; i < inputs.size(); i++) { -// String full = inputs.get(i); -// String command = full; -// List args = new ArrayList<>(); -// while (!command.isEmpty() && command.charAt(command.length() - 1) == ']') { -// int startPos = StringMan.findMatchingBracket(command, command.length() - 1); -// if (startPos == -1) break; -// String arg = command.substring(startPos + 1, command.length() - 1); -// args.add(arg); -// command = full.substring(0, startPos); -// } -// Collections.reverse(args); -// ParseEntry entry = new ParseEntry(full, command, i > 0 ? and.get(i - 1) : false); -// keys.add(new AbstractMap.SimpleEntry<>(entry, args)); -// } -// return keys; -// } -//} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/MaskCommands.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/MaskCommands.java deleted file mode 100644 index 019e309ff..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/MaskCommands.java +++ /dev/null @@ -1,132 +0,0 @@ -// TODO: Ping @MattBDev to reimplement (or remove because this class is stupid) 2020-02-04 -//package com.fastasyncworldedit.core.command; -// -//import com.boydti.fawe.object.mask.AdjacentAnyMask; -//import com.boydti.fawe.object.mask.AdjacentMask; -//import com.boydti.fawe.object.mask.AngleMask; -//import com.boydti.fawe.object.mask.BiomeMask; -//import com.boydti.fawe.object.mask.BlockLightMask; -//import com.boydti.fawe.object.mask.BrightnessMask; -//import com.boydti.fawe.object.mask.ExtremaMask; -//import com.boydti.fawe.object.mask.LightMask; -//import com.boydti.fawe.object.mask.OpacityMask; -//import com.boydti.fawe.object.mask.ROCAngleMask; -//import com.boydti.fawe.object.mask.RadiusMask; -//import com.boydti.fawe.object.mask.RandomMask; -//import com.boydti.fawe.object.mask.SimplexMask; -//import com.boydti.fawe.object.mask.SkyLightMask; -//import com.boydti.fawe.object.mask.SurfaceMask; -//import com.boydti.fawe.object.mask.WallMask; -//import com.boydti.fawe.function.mask.XAxisMask; -//import com.boydti.fawe.function.mask.YAxisMask; -//import com.boydti.fawe.function.mask.ZAxisMask; -//import com.sk89q.worldedit.IncompleteRegionException; -//import com.sk89q.worldedit.LocalSession; -//import com.sk89q.worldedit.WorldEdit; -//import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; -//import com.sk89q.worldedit.entity.Player; -//import com.sk89q.worldedit.extent.Extent; -//import com.sk89q.worldedit.function.mask.BlockMaskBuilder; -//import com.sk89q.worldedit.function.mask.ExistingBlockMask; -//import com.sk89q.worldedit.function.mask.ExpressionMask; -//import com.sk89q.worldedit.function.mask.Mask; -//import com.sk89q.worldedit.function.mask.MaskIntersection; -//import com.sk89q.worldedit.function.mask.MaskUnion; -//import com.sk89q.worldedit.function.mask.Masks; -//import com.sk89q.worldedit.function.mask.OffsetMask; -//import com.sk89q.worldedit.function.mask.RegionMask; -//import com.sk89q.worldedit.function.mask.SolidBlockMask; -//import com.sk89q.worldedit.internal.expression.Expression; -//import com.sk89q.worldedit.internal.expression.ExpressionEnvironment; -//import com.sk89q.worldedit.internal.expression.ExpressionException; -//import com.sk89q.worldedit.math.BlockVector3; -//import com.sk89q.worldedit.math.Vector3; -//import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; -//import com.sk89q.worldedit.session.request.RequestSelection; -//import com.sk89q.worldedit.world.biome.BiomeType; -//import org.enginehub.piston.annotation.Command; -//import org.enginehub.piston.annotation.CommandContainer; -//import org.enginehub.piston.annotation.param.Arg; -//import org.enginehub.piston.annotation.param.Switch; -// -////@Command(aliases = {"masks"}, -//// desc = "Help for the various masks. [More Info](https://git.io/v9r4K)", -//// descFooter = "Masks determine if a block can be placed\n" + -//// " - Use [brackets] for arguments\n" + -//// " - Use , to OR multiple\n" + -//// " - Use & to AND multiple\n" + -//// "e.g. >[stone,dirt],#light[0][5],$jungle\n" + -//// "More Info: https://git.io/v9r4K" -////) -//@CommandContainer//(superTypes = CommandPermissionsConditionGenerator.Registration.class) -//public class MaskCommands { -// private final WorldEdit worldEdit; -// -// public MaskCommands(WorldEdit worldEdit) { -// this.worldEdit = worldEdit; -// } -// @Command( -// name = "#light", -// desc = "Restrict to specific light levels" -// ) -// public Mask light(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) { -// return new LightMask(extent, (int) minInt, (int) maxInt); -// } -// -// @Command( -// name = "#skylight", -// desc = "Restrict to specific sky light levels" -// ) -// public Mask skylight(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) { -// return new SkyLightMask(extent, (int) minInt, (int) maxInt); -// } -// -// @Command( -// name = "#blocklight", -// aliases = {"#emittedlight"}, -// desc = "Restrict to specific block light levels" -// ) -// public Mask blocklight(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) { -// return new BlockLightMask(extent, (int) minInt, (int) maxInt); -// } -// -// @Command( -// name = "#opacity", -// desc = "Restrict to specific opacity levels" -// ) -// public Mask opacity(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) { -// return new OpacityMask(extent, (int) minInt, (int) maxInt); -// } -// -// @Command( -// name = "#brightness", -// desc = "Restrict to specific block brightness" -// ) -// public Mask brightness(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) { -// return new BrightnessMask(extent, (int) minInt, (int) maxInt); -// } -// -// @Command( -// name = "#haslight", -// desc = "Restricts to blocks with light (sky or emitted)" -// ) -// public Mask haslight(Extent extent) { -// return new LightMask(extent, 1, Integer.MAX_VALUE); -// } -// -// @Command( -// name = "#nolight", -// desc = "Restrict to blocks without light (sky or emitted)" -// ) -// public Mask nolight(Extent extent) { -// return new LightMask(extent, 0, 0); -// } - -// @Command( -// name = "#iddata", -// desc = "Restrict to initial block id and data" -// ) -// public Mask iddata(Extent extent) { -// return new IdDataMask(extent); -// } -//} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/PatternCommands.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/PatternCommands.java deleted file mode 100644 index 313eb8066..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/PatternCommands.java +++ /dev/null @@ -1,356 +0,0 @@ -// TODO: Ping @MattBDev to reimplement 2020-02-04 -//package com.sk89q.worldedit.command; -// -//import com.boydti.fawe.object.DataAnglePattern; -//import com.boydti.fawe.object.clipboard.MultiClipboardHolder; -//import com.boydti.fawe.object.collection.RandomCollection; -//import com.boydti.fawe.object.pattern.AngleColorPattern; -//import com.boydti.fawe.object.pattern.AverageColorPattern; -//import com.boydti.fawe.object.pattern.BiomePattern; -//import com.boydti.fawe.object.pattern.BufferedPattern; -//import com.boydti.fawe.object.pattern.BufferedPattern2D; -//import com.boydti.fawe.object.pattern.DataPattern; -//import com.boydti.fawe.object.pattern.DesaturatePattern; -//import com.boydti.fawe.object.pattern.ExistingPattern; -//import com.boydti.fawe.object.pattern.ExpressionPattern; -//import com.boydti.fawe.object.pattern.FullClipboardPattern; -//import com.boydti.fawe.object.pattern.IdDataMaskPattern; -//import com.boydti.fawe.object.pattern.IdPattern; -//import com.boydti.fawe.object.pattern.Linear2DBlockPattern; -//import com.boydti.fawe.object.pattern.Linear3DBlockPattern; -//import com.boydti.fawe.object.pattern.LinearBlockPattern; -//import com.boydti.fawe.object.pattern.MaskedPattern; -//import com.boydti.fawe.object.pattern.NoXPattern; -//import com.boydti.fawe.object.pattern.NoYPattern; -//import com.boydti.fawe.object.pattern.NoZPattern; -//import com.boydti.fawe.object.pattern.OffsetPattern; -//import com.boydti.fawe.object.pattern.PropertyPattern; -//import com.boydti.fawe.object.pattern.RandomFullClipboardPattern; -//import com.boydti.fawe.object.pattern.RandomOffsetPattern; -//import com.boydti.fawe.object.pattern.RelativePattern; -//import com.boydti.fawe.object.pattern.SaturatePattern; -//import com.boydti.fawe.object.pattern.ShadePattern; -//import com.boydti.fawe.object.pattern.SolidRandomOffsetPattern; -//import com.boydti.fawe.object.pattern.SurfaceRandomOffsetPattern; -//import com.boydti.fawe.object.random.SimplexRandom; -//import com.boydti.fawe.util.ColorUtil; -//import com.boydti.fawe.util.TextureUtil; -//import com.sk89q.worldedit.EmptyClipboardException; -//import com.sk89q.worldedit.LocalSession; -//import com.sk89q.worldedit.entity.Player; -//import com.sk89q.worldedit.extension.input.InputParseException; -//import com.sk89q.worldedit.extension.platform.Actor; -//import com.sk89q.worldedit.extent.Extent; -//import com.sk89q.worldedit.extent.clipboard.Clipboard; -//import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; -//import com.sk89q.worldedit.function.mask.Mask; -//import com.sk89q.worldedit.function.pattern.ClipboardPattern; -//import com.sk89q.worldedit.function.pattern.Pattern; -//import com.sk89q.worldedit.function.pattern.RandomPattern; -//import com.sk89q.worldedit.internal.expression.Expression; -//import com.sk89q.worldedit.internal.expression.ExpressionException; -//import com.sk89q.worldedit.math.Vector3; -//import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; -//import com.sk89q.worldedit.session.ClipboardHolder; -//import com.sk89q.worldedit.world.biome.BiomeType; -//import java.awt.Color; -//import java.io.IOException; -//import java.util.Collections; -//import java.util.List; -//import java.util.Set; -//import org.enginehub.piston.annotation.Command; -//import org.enginehub.piston.annotation.CommandContainer; -//import org.enginehub.piston.annotation.param.Arg; -//import org.jetbrains.annotations.Range; -// -////@Command(aliases = {"patterns"}, -//// desc = "Help for the various patterns. [More Info](https://git.io/vSPmA)", -//// descFooter = "Patterns determine what blocks are placed\n" + -//// " - Use [brackets] for arguments\n" + -//// " - Use , to OR multiple\n" + -//// "e.g., #surfacespread[10][#existing],andesite\n" + -//// "More Info: https://git.io/vSPmA" -////) -//@CommandContainer//(superTypes = CommandPermissionsConditionGenerator.Registration.class) -//public class PatternCommands { -// -// -// @Command( -// name = "#simplex", -// desc = "Use simplex noise to randomize blocks. Tutorial: https://imgur.com/a/rwVAE" -//) -// public Pattern simplex(@Arg(desc = "scale factor") double scale, @Arg(desc = "Pattern") Pattern other) { -// if (other instanceof RandomPattern) { -// scale = (1d / Math.max(1, scale)); -// RandomCollection collection = ((RandomPattern) other).getCollection(); -// collection.setRandom(new SimplexRandom(scale)); -// } -// return other; -// } -// -// @Command( -// name = "#color", -// desc = "Use the block closest to a specific color" -//) -// public Pattern color(TextureUtil textureUtil, @Arg(desc = "String color") String color) { -// Color colorObj = ColorUtil.parseColor(color); -// return textureUtil.getNearestBlock(colorObj.getRGB()).getDefaultState(); -// } -// -// @Command( -// name = "#anglecolor", -// desc = "A darker block based on the existing terrain angle" -//) -// public Pattern anglecolor(Extent extent, LocalSession session, @Arg(desc = "int", def = "1") int distance) { -// return new AngleColorPattern(extent, session, distance); -// } -// -// @Command( -// name = "#angledata", -// desc = "Block data based on the existing terrain angle" -// ) -// public Pattern angledata(Extent extent, @Arg(desc = "int", def = "1") int distance) { -// return new DataAnglePattern(extent, distance); -// } -// -// @Command( -// name = "#saturate", -// desc = "Saturate the existing block with a color" -//) -// public Pattern saturate(Extent extent, LocalSession session, @Arg(desc = "Color code") String colorStr) { -// Color color = ColorUtil.parseColor(colorStr); -// return new SaturatePattern(extent, color.getRGB(), session); -// } -// -// @Command( -// name = "#averagecolor", -// desc = "Average between the existing block and a color" -//) -// public Pattern averagecolor(Extent extent, LocalSession session, @Arg(desc = "Color code") String colorStr) { -// Color color = ColorUtil.parseColor(colorStr); -// return new AverageColorPattern(extent, color.getRGB(), session); -// } -// -// @Command( -// name = "#desaturate", -// desc = "Desaturated color of the existing block" -//) -// public Pattern desaturate(Extent extent, LocalSession session, @Arg(desc = "double", def = "100") double percent) { -// return new DesaturatePattern(extent, percent / 100d, session); -// } -// -// @Command( -// name = "#lighten", -// desc = "Lighten the existing block" -//) -// public Pattern lighten(Extent extent, TextureUtil util) { -// return new ShadePattern(extent, false, util); -// } -// -// @Command( -// name = "#darken", -// desc = "Darken the existing block" -//) -// public Pattern darken(Extent extent, TextureUtil util) { -// return new ShadePattern(extent, true, util); -// } -// -// @Command( -// name = "#buffer", -// desc = "Only place a block once while a pattern is in use", -// descFooter = "Only place a block once while a pattern is in use\n" + -// "Use with a brush when you don't want to apply to the same spot twice" -//) -// public Pattern buffer(Actor actor, @Arg(desc = "Pattern")Pattern pattern) { -// return new BufferedPattern(actor, pattern); -// } -// -// @Command( -// name = "#buffer2d", -// desc = "Only place a block once in a column while a pattern is in use" -//) -// public Pattern buffer2d(Actor actor, @Arg(desc = "Pattern")Pattern pattern) { -// return new BufferedPattern2D(actor, pattern); -// } -// -// @Command( -// name = "#iddatamask", -// desc = "Use the pattern's id and the existing blocks data with the provided mask", -// descFooter = "Use the pattern's id and the existing blocks data with the provided mask\n" + -// " - Use to replace slabs or where the data values needs to be shifted instead of set" -//) -// public Pattern iddatamask(Extent extent, @Range(from = 0, to = 15) @Arg(desc = "bit mask") int bitmask, @Arg(desc = "Pattern")Pattern pattern) { -// -// return new IdDataMaskPattern(extent, pattern, bitmask); -// } -// -// @Command( -// name = "#id", -// desc = "Only change the block id" -//) -// public Pattern id(Extent extent, @Arg(desc = "Pattern")Pattern pattern) { -// -// return new IdPattern(extent, pattern); -// } -// -// @Command( -// name = "#data", -// desc = "Only change the block data" -//) -// public Pattern data(Extent extent, @Arg(desc = "Pattern")Pattern pattern) { -// -// return new DataPattern(extent, pattern); -// } -// -// @Command( -// name = "#biome", -// aliases = {"$"}, -// desc = "Set the biome" -//) -// public Pattern biome(Extent extent, @Arg(desc = "Biome type") BiomeType biome) { -// -// return new BiomePattern(extent, biome); -// } -// -// @Command( -// name = "#relative", -// aliases = {"#~", "#r", "#rel"}, -// desc = "Offset the pattern to where you click" -//) -// public Pattern relative(@Arg(desc = "Pattern")Pattern pattern) { -// -// return new RelativePattern(pattern); -// } -// -// @Command( -// name = "#!x", -// aliases = {"#nx", "#nox"}, -// desc = "The pattern will not be provided the x axis info", -// descFooter = "The pattern will not be provided the z axis info.\n" + -// "Example: #!x[#!z[#~[#l3d[pattern]]]]" -//) -// public Pattern nox(@Arg(desc = "Pattern")Pattern pattern) { -// -// return new NoXPattern(pattern); -// } -// -// @Command( -// name = "#!y", -// aliases = {"#ny", "#noy"}, -// desc = "The pattern will not be provided the y axis info" -//) -// public Pattern noy(@Arg(desc = "Pattern")Pattern pattern) { -// -// return new NoYPattern(pattern); -// } -// -// @Command( -// name = "#!z", -// aliases = {"#nz", "#noz"}, -// desc = "The pattern will not be provided the z axis info" -//) -// public Pattern noz(@Arg(desc = "Pattern")Pattern pattern) { -// -// return new NoZPattern(pattern); -// } -// -// @Command( -// name = "#mask", -// desc = "Apply a pattern depending on a mask" -//) -// public Pattern mask(@Arg(desc = "Mask") Mask mask, @Arg(desc = "Pattern")Pattern pass, @Arg(desc = "Pattern")Pattern fail) { -// return new MaskedPattern(mask, pass, fail); -// } -// -// @Command( -// name = "#offset", -// desc = "Offset a pattern" -//) -// public Pattern offset(@Arg(desc = "x offset") double x, @Arg(desc = "y offset") double y, @Arg(desc = "z offset") double z, @Arg(desc = "Pattern")Pattern pattern) { -// -// return new OffsetPattern(pattern, (int) x, (int) y, (int) z); -// } -// -// @Command( -// name = "#surfacespread", -// desc = "Applies to only blocks on a surface. Selects a block from provided pattern with a given randomized offset `[0, )`. e.g., Use `#existing` to randomly offset blocks in the world, or `#copy` to offset blocks in your clipboard" -//) -// public Pattern surfacespread(@Arg(desc = "spread distance (blocks)") double distance, @Arg(desc = "Pattern")Pattern pattern) { -// -// return new SurfaceRandomOffsetPattern(pattern, (int) distance); -// } -// -// @Command( -// name = "#solidspread", -// desc = "Randomly spread solid blocks" -//) -// public Pattern solidspread(@Arg(desc = "x offset") double x, @Arg(desc = "y offset") double y, @Arg(desc = "z offset") double z, @Arg(desc = "Pattern")Pattern pattern) { -// -// return new SolidRandomOffsetPattern(pattern, (int) x, (int) y, (int) z); -// } -// -// @Command( -// name = "#spread", -// aliases = {"#randomoffset"}, -// desc = "Randomly spread blocks" -//) -// public Pattern spread(@Arg(desc = "x offset") double x, @Arg(desc = "y offset") double y, @Arg(desc = "z offset") double z, @Arg(desc = "Pattern")Pattern pattern) { -// -// return new RandomOffsetPattern(pattern, (int) x, (int) y, (int) z); -// } -// -// @Command( -// name = "#linear", -// aliases = {"#l"}, -// desc = "Sequentially set blocks from a list of patterns" -//) -// public Pattern linear(@Arg(desc = "Pattern") Pattern other) { -// -// if (other instanceof RandomPattern) { -// Set patterns = ((RandomPattern) other).getPatterns(); -// return new LinearBlockPattern(patterns.toArray(new Pattern[patterns.size()])); -// } -// return other; -// } -// -// @Command( -// name = "#linear3d", -// aliases = {"#l3d"}, -// desc = "Use the x,y,z coordinate to pick a block from the list" -//) -// public Pattern linear3d(@Arg(desc = "Pattern") Pattern other) { -// -// if (other instanceof RandomPattern) { -// Set patterns = ((RandomPattern) other).getPatterns(); -// return new Linear3DBlockPattern(patterns.toArray(new Pattern[patterns.size()])); -// } -// return other; -// } -// -// @Command( -// name = "#linear2d", -// aliases = {"#l2d"}, -// desc = "Use the x,z coordinate to pick a block from the list" -//) -// public Pattern linear2d(@Arg(desc = "Pattern") Pattern other) { -// -// if (other instanceof RandomPattern) { -// Set patterns = ((RandomPattern) other).getPatterns(); -// return new Linear2DBlockPattern(patterns.toArray(new Pattern[patterns.size()])); -// } -// return other; -// } -// -// @Command( -// name = "=", -// aliases = {"#=", "#expression"}, -// desc = "Expression pattern: http://wiki.sk89q.com/wiki/WorldEdit/Expression_syntax" -//) -// public Pattern expression(Extent extent, @Arg(desc = "Expression") String input) throws ExpressionException { -// -// Expression exp = Expression.compile(input, "x", "y", "z"); -// WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment(extent, Vector3.ONE, Vector3.ZERO); -// exp.setEnvironment(env); -// return new ExpressionPattern(exp); -// } -//} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/TransformCommands.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/TransformCommands.java deleted file mode 100644 index db631711a..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/TransformCommands.java +++ /dev/null @@ -1,105 +0,0 @@ -// TODO: Ping @MattBDev to reimplement 2020-02-04 -//package com.sk89q.worldedit.command; -// -//import com.boydti.fawe.object.extent.Linear3DTransform; -//import com.boydti.fawe.object.extent.LinearTransform; -//import com.boydti.fawe.object.extent.OffsetExtent; -//import com.boydti.fawe.object.extent.PatternTransform; -//import com.boydti.fawe.object.extent.RandomOffsetTransform; -//import com.boydti.fawe.object.extent.RandomTransform; -//import com.boydti.fawe.object.extent.ResettableExtent; -//import com.boydti.fawe.object.extent.ScaleTransform; -//import com.boydti.fawe.object.extent.TransformExtent; -//import com.boydti.fawe.util.ExtentTraverser; -//import com.sk89q.worldedit.LocalSession; -//import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; -//import com.sk89q.worldedit.entity.Player; -//import com.sk89q.worldedit.extension.platform.Actor; -//import com.sk89q.worldedit.extent.transform.BlockTransformExtent; -//import com.sk89q.worldedit.function.pattern.Pattern; -//import com.sk89q.worldedit.math.transform.AffineTransform; -//import java.util.Set; -//import org.enginehub.piston.annotation.Command; -//import org.enginehub.piston.annotation.CommandContainer; -//import org.enginehub.piston.annotation.param.Arg; -// -//@CommandContainer//(superTypes = CommandPermissionsConditionGenerator.Registration.class) -//public class TransformCommands { -// -// @Command( -// name = "#linear", -// aliases = {"#l"}, -// desc = "Sequentially pick from a list of transform" -// ) -// public ResettableExtent linear(Actor actor, LocalSession session, @Arg(name = "other", desc = "ResettableExtent", def = "#null") ResettableExtent other) { -// if (other instanceof RandomTransform) { -// Set extents = ((RandomTransform) other).getExtents(); -// return new LinearTransform(extents.toArray(new ResettableExtent[0])); -// } -// return other; -// } -// -// @Command( -// name = "#linear3d", -// aliases = {"#l3d"}, -// desc = "Use the x,y,z coordinate to pick a transform from the list" -// ) -// public ResettableExtent linear3d(Actor actor, LocalSession session, @Arg(name = "other", desc = "ResettableExtent", def = "#null") ResettableExtent other) { -// if (other instanceof RandomTransform) { -// Set extents = ((RandomTransform) other).getExtents(); -// return new Linear3DTransform(extents.toArray(new ResettableExtent[0])); -// } -// return other; -// } -// -// @Command( -// name = "#pattern", -// desc = "Always use a specific pattern" -// ) -// public ResettableExtent pattern(Actor actor, LocalSession session, @Arg(desc = "Pattern") Pattern pattern, @Arg(name = "other", desc = "ResettableExtent", def = "#null") ResettableExtent other) { -// return new PatternTransform(other, pattern); -// } -// -// @Command( -// name = "#offset", -// desc = "Offset transform" -// ) -// public ResettableExtent offset(Actor actor, LocalSession session, double x, double y, double z, @Arg(name = "other", desc = "ResettableExtent", def = "#null") ResettableExtent other) { -// return new OffsetExtent(other, (int) x, (int) y, (int) z); -// } -// -// @Command( -// name = "#spread", -// aliases = {"#randomoffset"}, -// desc = "Random offset transform" -//) -// public ResettableExtent randomOffset(Actor actor, LocalSession session, double x, double y, double z, @Arg(name = "other", desc = "ResettableExtent", def = "#null") ResettableExtent other) { -// return new RandomOffsetTransform(other, (int) x, (int) y, (int) z); -// } -// -// @Command( -// name = "#scale", -// desc = "All changes will be scaled" -// ) -// public ResettableExtent scale(Actor actor, LocalSession session, double x, double y, double z, @Arg(name = "other", desc = "ResettableExtent", def = "#null") ResettableExtent other) { -// return new ScaleTransform(other, x, y, z); -// } -// -// @Command( -// name = "#rotate", -// desc = "All changes will be rotate around the initial position" -// ) -// public ResettableExtent rotate(Player player, LocalSession session, double x, double y, double z, @Arg(name = "other", desc = "ResettableExtent", def = "#null") ResettableExtent other) { -// ExtentTraverser traverser = new ExtentTraverser<>(other).find(TransformExtent.class); -// BlockTransformExtent affine = traverser != null ? traverser.get() : null; -// if (affine == null) { -// other = affine = new TransformExtent(other); -// } -// AffineTransform transform = (AffineTransform) affine.getTransform(); -// transform = transform.rotateX(x); -// transform = transform.rotateY(y); -// transform = transform.rotateZ(z); -// affine.setTransform(transform); -// return other; -// } -//} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ImageBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ImageBrush.java index 350fa1637..318ab0bb7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ImageBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ImageBrush.java @@ -18,6 +18,8 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; import java.awt.image.BufferedImage; import java.io.IOException; @@ -54,8 +56,14 @@ public class ImageBrush implements Brush { default: BlockState block = extent.getBlock(pos); TextureUtil tu = session.getTextureUtil(); - int existingColor = tu.getColor(block.getBlockType()); - return tu.combineTransparency(color, existingColor); + BlockType type = block.getBlockType(); + int existingColor; + if (type == BlockTypes.GRASS_BLOCK) { + existingColor = tu.getColor(extent.getBiome(pos)); + } else { + existingColor = tu.getColor(type); + } + return TextureUtil.combineTransparency(color, existingColor); } }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/DefaultTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/DefaultTransformParser.java deleted file mode 100644 index bb7f10851..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/DefaultTransformParser.java +++ /dev/null @@ -1,136 +0,0 @@ -// TODO: Ping @MattBDev to reimplement 2020-02-04 -//package com.sk89q.worldedit.extension.factory; -// -//import com.boydti.fawe.command.FaweParser; -//import com.boydti.fawe.command.SuggestInputParseException; -//import com.boydti.fawe.object.extent.MultiTransform; -//import com.boydti.fawe.object.extent.RandomTransform; -//import com.boydti.fawe.object.extent.ResettableExtent; -//import com.boydti.fawe.object.random.TrueRandom; -//import com.boydti.fawe.util.StringMan; -//import com.google.common.collect.Iterables; -//import com.sk89q.minecraft.util.commands.CommandLocals; -//import com.sk89q.worldedit.WorldEdit; -////import com.sk89q.worldedit.command.TransformCommands; -//import com.sk89q.worldedit.extension.input.InputParseException; -//import com.sk89q.worldedit.extension.input.NoMatchException; -//import com.sk89q.worldedit.extension.input.ParserContext; -//import com.sk89q.worldedit.extension.platform.Actor; -//import com.sk89q.worldedit.internal.expression.Expression; -//import java.util.ArrayList; -//import java.util.List; -//import java.util.Map; -// -//public class DefaultTransformParser extends FaweParser { -// -// public DefaultTransformParser(WorldEdit worldEdit) { -// super(worldEdit, "transforms"); -// } -// -// @Override -// public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException { -// if (input.isEmpty()) return null; -// -// List unionChances = new ArrayList<>(); -// List intersectionChances = new ArrayList<>(); -// -// List intersection = new ArrayList<>(); -// List union = new ArrayList<>(); -// final CommandLocals locals = new CommandLocals(); -// Actor actor = context != null ? context.getActor() : null; -// if (actor != null) { -// locals.put(Actor.class, actor); -// } -// try { -// List>> parsed = parse(input); -// for (Map.Entry> entry : parsed) { -// ParseEntry pe = entry.getKey(); -// String command = pe.input; -// ResettableExtent transform; -// double chance = 1; -// if (command.isEmpty()) { -// transform = parseFromInput(StringMan.join(entry.getValue(), ','), context); -// } else { -// List args = entry.getValue(); -// String cmdArgs = ((args.isEmpty()) ? "" : " " + StringMan.join(args, " ")); -// try { -// transform = parse(command + cmdArgs, context); -// } catch (SuggestInputParseException rethrow) { -// throw rethrow; -// } catch (Throwable e) { -// throw new NoMatchException("See: //transforms"); -// } -// if (transform == null) { -// // Legacy syntax -// int percentIndex = command.indexOf('%'); -// if (percentIndex != -1) { // Legacy percent pattern -// chance = Expression.compile(command.substring(0, percentIndex)).evaluate(); -// command = command.substring(percentIndex + 1); -// if (!entry.getValue().isEmpty()) { -// if (!command.isEmpty()) command += " "; -// command += StringMan.join(entry.getValue(), " "); -// } -// transform = parseFromInput(command, context); -// } else { -// throw new NoMatchException("See: //transforms"); -// } -// } -// if (pe.and) { // & -// intersectionChances.add(chance); -// intersection.add(transform); -// } else { -// if (!intersection.isEmpty()) { -// if (intersection.size() == 1) { -// throw new InputParseException("Error, floating &"); -// } -// MultiTransform multi = new MultiTransform(); -// double total = 0; -// for (int i = 0; i < intersection.size(); i++) { -// Double value = intersectionChances.get(i); -// total += value; -// multi.add(intersection.get(i), value); -// } -// union.add(multi); -// unionChances.add(total); -// intersection.clear(); -// intersectionChances.clear(); -// } -// unionChances.add(chance); -// union.add(transform); -// } -// } -// } -// } catch (Throwable e) { -// throw new InputParseException(e.getMessage(), e); -// } -// if (!intersection.isEmpty()) { -// if (intersection.size() == 1) { -// throw new InputParseException("Error, floating &"); -// } -// MultiTransform multi = new MultiTransform(); -// double total = 0; -// for (int i = 0; i < intersection.size(); i++) { -// Double value = intersectionChances.get(i); -// total += value; -// multi.add(intersection.get(i), value); -// } -// union.add(multi); -// unionChances.add(total); -// intersection.clear(); -// intersectionChances.clear(); -// } -// if (union.isEmpty()) { -// throw new NoMatchException("See: //transforms"); -// } else if (union.size() == 1) { -// return union.get(0); -// } else { -// RandomTransform random = new RandomTransform(new TrueRandom()); -// for (int i = 0; i < union.size(); i++) { -// random.add(union.get(i), unionChances.get(i)); -// } -// return random; -// } -// } -// -// -//} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/TransformFactory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/TransformFactory.java new file mode 100644 index 000000000..40f0b65a7 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/TransformFactory.java @@ -0,0 +1,144 @@ +package com.fastasyncworldedit.core.extension.factory; + +import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extension.factory.parser.transform.RichTransformParser; +import com.fastasyncworldedit.core.extension.factory.parser.transform.Linear3DTransformParser; +import com.fastasyncworldedit.core.extension.factory.parser.transform.LinearTransformParser; +import com.fastasyncworldedit.core.extension.factory.parser.transform.OffsetTransformParser; +import com.fastasyncworldedit.core.extension.factory.parser.transform.PatternTransformParser; +import com.fastasyncworldedit.core.extension.factory.parser.transform.RandomTransformParser; +import com.fastasyncworldedit.core.extension.factory.parser.transform.RotateTransformParser; +import com.fastasyncworldedit.core.extension.factory.parser.transform.ScaleTransformParser; +import com.fastasyncworldedit.core.extension.factory.parser.transform.SpreadTransformParser; +import com.fastasyncworldedit.core.extent.ResettableExtent; +import com.fastasyncworldedit.core.extent.transform.RandomTransform; +import com.fastasyncworldedit.core.math.random.TrueRandom; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.internal.registry.AbstractFactory; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import java.util.ArrayList; +import java.util.List; + +public class TransformFactory extends AbstractFactory { + + private final RichTransformParser richTransformParser; + + /** + * Create a new factory. + * + * @param worldEdit the WorldEdit instance + */ + public TransformFactory(WorldEdit worldEdit) { + super(worldEdit, new NullTransformParser(worldEdit)); + + richTransformParser = new RichTransformParser(worldEdit); + + // split and parse each sub-transform + register(new RandomTransformParser(worldEdit)); + + register(new OffsetTransformParser(worldEdit)); + register(new ScaleTransformParser(worldEdit)); + register(new RotateTransformParser(worldEdit)); + register(new SpreadTransformParser(worldEdit)); + register(new PatternTransformParser(worldEdit)); + register(new LinearTransformParser(worldEdit)); + register(new Linear3DTransformParser(worldEdit)); + } + + @Override + public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException { + List transforms = new ArrayList<>(); + + for (String component : input.split(" ")) { + if (component.isEmpty()) { + continue; + } + + ResettableExtent match = richTransformParser.parseFromInput(component, context); + if (match != null) { + transforms.add(match); + continue; + } + parseFromParsers(context, transforms, component); + } + + return getResettableExtent(input, transforms); + } + + private void parseFromParsers( + final ParserContext context, + final List transforms, + final String component + ) { + ResettableExtent match = null; + for (InputParser parser : getParsers()) { + match = parser.parseFromInput(component, context); + + if (match != null) { + break; + } + } + if (match == null) { + throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); + } + transforms.add(match); + } + + /** + * Parses a transform without considering parsing through the {@link RichTransformParser}, therefore not accepting + * "richer" parsing where & and , are used. Exists to prevent stack overflows. + * + * @param input input string + * @param context input context + * @return parsed result + * @throws InputParseException if no result found + */ + public ResettableExtent parseWithoutRich(String input, ParserContext context) throws InputParseException { + List transforms = new ArrayList<>(); + + for (String component : input.split(" ")) { + if (component.isEmpty()) { + continue; + } + + parseFromParsers(context, transforms, component); + } + + return getResettableExtent(input, transforms); + } + + private ResettableExtent getResettableExtent(final String input, final List transforms) { + switch (transforms.size()) { + case 0: + throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); + case 1: + return transforms.get(0); + default: + RandomTransform randomTransform = new RandomTransform(new TrueRandom()); + for (ResettableExtent transform : transforms) { + randomTransform.add(transform, 1d); + } + return randomTransform; + } + } + + // TODO is there a better default? + private static final class NullTransformParser extends InputParser { + + private NullTransformParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException { + return null; + } + + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/AliasedParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/AliasedParser.java new file mode 100644 index 000000000..22f9fc367 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/AliasedParser.java @@ -0,0 +1,14 @@ +package com.fastasyncworldedit.core.extension.factory.parser; + +import java.util.List; + +public interface AliasedParser { + + /** + * The strings this parser matches. + * + * @return the matching aliases + */ + List getMatchedAliases(); + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java new file mode 100644 index 000000000..a17149194 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java @@ -0,0 +1,134 @@ +package com.fastasyncworldedit.core.extension.factory.parser; + +import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.util.StringMan; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.platform.PlatformCommandManager; +import com.sk89q.worldedit.internal.registry.InputParser; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public abstract class FaweParser extends InputParser implements AliasedParser { + + protected FaweParser(WorldEdit worldEdit) { + super(worldEdit); + } + + /** + * Parse an input into a list of {@link java.util.Map.Entry} of {@link ParseEntry} and a list of the given arguments, where + * arguments are given in square brackets, e.g. {@code #offset[2][10][2]}. Different entries may be separated by , or & + * (OR and AND respectively) + * + * @param toParse the string to parse + * @return a list of parsed entries and their arguments + * @throws InputParseException if the input is not complete (has dangling characters) + */ + public static List>> parse(String toParse) throws InputParseException { + List>> keys = new ArrayList<>(); + List inputs = new ArrayList<>(); + List and = new ArrayList<>(); + int last = 0; + outer: + for (int i = 0; i < toParse.length(); i++) { + char c = toParse.charAt(i); + switch (c) { + case ',': + case '&': + String result = toParse.substring(last, i); + if (!result.isEmpty()) { + inputs.add(result); + and.add(c == '&'); + } else { + throw new InputParseException(Caption.of("fawe.error.parse.invalid-dangling-character", c)); + } + last = i + 1; + continue outer; + default: + if (c == '[') { + int next = StringMan.findMatchingBracket(toParse, i); + if (next != -1) { + i = next; + } else { + toParse += "]"; + i = toParse.length(); + } + } + } + } + inputs.add(toParse.substring(last)); + for (int i = 0; i < inputs.size(); i++) { + String full = inputs.get(i); + String command = full; + List args = new ArrayList<>(); + while (!command.isEmpty() && command.charAt(command.length() - 1) == ']') { + int startPos = StringMan.findMatchingBracket(command, command.length() - 1); + if (startPos == -1) { + break; + } + String arg = command.substring(startPos + 1, command.length() - 1); + args.add(arg); + command = full.substring(0, startPos); + } + Collections.reverse(args); + ParseEntry entry = new ParseEntry(full, command, i > 0 ? and.get(i - 1) : false); + keys.add(new AbstractMap.SimpleEntry<>(entry, args)); + } + return keys; + } + + protected PlatformCommandManager getPlatform() { + return PlatformCommandManager.getInstance(); + } + + public static class ParseEntry { + + private final boolean and; + private final String input; + private final String full; + + public ParseEntry(String full, String input, boolean type) { + this.full = full; + this.input = input; + this.and = type; + } + + /** + * Gives if the parsed entry was appended to the original input as an AND. + * + * @return if appended to input with '&' rather than ',' + */ + public boolean isAnd() { + return and; + } + + /** + * The input "name" e.g. for {@code #offset[2][10][2]}, returns "offset" + * + * @return input name + */ + public String getInput() { + return input; + } + + /** + * The original full input, including arguments e.g. for {@code #offset[2][10][2]}, returns "#offset[2][10][2]" + * + * @return original full input + */ + public String getFull() { + return full; + } + + @Override + public String toString() { + return input + " | " + and; + } + + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java index 0dabf6d85..3f06df9a9 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java @@ -22,7 +22,7 @@ import java.util.stream.Stream; * * @param the parse result. */ -public abstract class RichParser extends InputParser { +public abstract class RichParser extends InputParser implements AliasedParser { private final String[] prefixes; @@ -51,7 +51,7 @@ public abstract class RichParser extends InputParser { @Nonnull private Function> extractArguments(String input) { return prefix -> { - if (input.length() > prefix.length()) { + if (input.length() > prefix.length() && prefix.startsWith(input + "[")) { // input already contains argument(s) -> extract them String[] strings = extractArguments(input.substring(prefix.length()), false); // rebuild the argument string without the last argument @@ -69,10 +69,24 @@ public abstract class RichParser extends InputParser { }; } + /** + * Gives the default prefix/name of the pattern/mask/transform. + * + * @return default prefix + */ public String getPrefix() { return this.prefixes[0]; } + /** + * Return all prefix/name aliases of the pattern/mask/transform + * + * @return all prefix/name aliases + */ + public List getMatchedAliases() { + return Arrays.asList(prefixes); + } + @Override public Stream getSuggestions(String input) { return Arrays.stream(this.prefixes) @@ -140,8 +154,15 @@ public abstract class RichParser extends InputParser { } } } - if (!requireClosing && open > 0) { - arguments.add(input.substring(openIndex + 1)); + if (!requireClosing) { + if (open > 0) { + arguments.add(input.substring(openIndex + 1)); + } else { + int last = input.lastIndexOf(']'); + if (last != -1) { + arguments.add(input.substring(last)); + } + } } if (requireClosing && open != 0) { throw new InputParseException(Caption.of("fawe.error.invalid-bracketing", TextComponent.of("'[' or ']'?"))); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/DefaultMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/DefaultMaskParser.java deleted file mode 100644 index 17075b403..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/DefaultMaskParser.java +++ /dev/null @@ -1,189 +0,0 @@ -// TODO: Ping @MattBDev to reimplement 2020-02-04 -//* -//package com.fastasyncworldedit.core.extension.factory.parser.mask; -// -//import com.boydti.fawe.command.FaweParser; -//import com.boydti.fawe.command.SuggestInputParseException; -//import com.boydti.fawe.config.Caption; -//import com.boydti.fawe.util.StringMan; -//import com.sk89q.minecraft.util.commands.CommandLocals; -//import com.sk89q.worldedit.WorldEdit; -//import com.sk89q.worldedit.extension.input.InputParseException; -//import com.sk89q.worldedit.extension.input.ParserContext; -//import com.sk89q.worldedit.extension.platform.Actor; -//import com.sk89q.worldedit.extent.Extent; -//import com.sk89q.worldedit.function.mask.BlockMaskBuilder; -//import com.sk89q.worldedit.function.mask.Mask; -//import com.sk89q.worldedit.function.mask.MaskIntersection; -//import com.sk89q.worldedit.function.mask.MaskUnion; -//import com.sk89q.worldedit.session.request.Request; -//import com.sk89q.worldedit.world.block.BaseBlock; -//import com.sk89q.worldedit.world.block.BlockStateHolder; -//import com.sk89q.worldedit.world.block.BlockTypes; -// -//import java.util.ArrayList; -//import java.util.List; -//import java.util.Map; -//import java.util.stream.Collectors; -//import java.util.stream.Stream; -// -//public class DefaultMaskParser extends FaweParser { -// public DefaultMaskParser(WorldEdit worldEdit) { -// super(worldEdit, "masks"); -// } -// -// @Override -// public Mask parseFromInput(String input, ParserContext context) throws InputParseException { -// if (input.isEmpty()) { -// throw new SuggestInputParseException("No input provided", "", () -> Stream.concat(Stream.of("#", ",", "&"), BlockTypes.getNameSpaces().stream().map(n -> n + ":")).collect(Collectors.toList())); -// } -// Extent extent = Request.request().getExtent(); -// if (extent == null) extent = context.getExtent(); -// List> masks = new ArrayList<>(); -// masks.add(new ArrayList<>()); -// -// final CommandLocals locals = new CommandLocals(); -// Actor actor = context != null ? context.getActor() : null; -// if (actor != null) { -// locals.put(Actor.class, actor); -// } -// try { -// List>> parsed = parse(input); -// for (Map.Entry> entry : parsed) { -// ParseEntry pe = entry.getKey(); -// final String command = pe.input; -// String full = pe.full; -// Mask mask = null; -// if (command.isEmpty()) { -// mask = parseFromInput(StringMan.join(entry.getValue(), ','), context); -// } else { -// List args = entry.getValue(); -// String cmdArgs = ((args.isEmpty()) ? "" : " " + StringMan.join(args, " ")); -// try { -// mask = parse(command + cmdArgs, context); -// } catch (SuggestInputParseException rethrow) { -// throw rethrow; -// } catch (Throwable e) { -// // TODO NOT IMPLEMENTED -//// throw SuggestInputParseException.of(e, full, () -> { -//// try { -//// List suggestions = dispatcher.get(command).getCallable().getSuggestions(cmdArgs, locals); -//// if (suggestions.size() <= 2) { -//// for (int i = 0; i < suggestions.size(); i++) { -//// String suggestion = suggestions.get(i); -//// if (suggestion.indexOf(' ') != 0) { -//// String[] split = suggestion.split(" "); -//// suggestion = "[" + StringMan.join(split, "][") + "]"; -//// suggestions.set(i, suggestion); -//// } -//// } -//// } -//// return suggestions; -//// } catch (CommandException e1) { -//// throw new InputParseException(e1.getMessage()); -//// } catch (Throwable e2) { -//// e2.printStackTrace(); -//// throw new InputParseException(e2.getMessage()); -//// } -//// }); -// } -// if (mask == null) { -// // Legacy patterns -// char char0 = command.charAt(0); -// boolean charMask = input.length() > 1 && input.charAt(1) != '['; -// if (charMask && input.charAt(0) == '=') { -// return parseFromInput(char0 + "[" + input.substring(1) + "]", context); -// } -// if (char0 == '#' || char0 == '?') { -// // TODO NOT IMPLEMENTED -//// throw new SuggestInputParseException(new NoMatchException("Unknown mask: " + full + ", See: //masks"), full, -//// () -> { -//// if (full.length() == 1) return new ArrayList<>(dispatcher.getPrimaryAliases()); -//// return dispatcher.getAliases().stream().filter( -//// s -> s.startsWith(command.toLowerCase(Locale.ROOT)) -//// ).collect(Collectors.toList()); -//// } -//// ); -// } -// // Legacy syntax -// if (charMask) { -// switch (char0) { -// case '\\': // -// case '/': // -// case '{': // -// case '$': // -// case '%': { -// String value = command.substring(1) + ((entry.getValue().isEmpty()) ? "" : "[" + StringMan.join(entry.getValue(), "][") + "]"); -// if (value.contains(":")) { -// if (value.charAt(0) == ':') value.replaceFirst(":", ""); -// value = value.replaceAll(":", "]["); -// } -// mask = parseFromInput("#" + char0 + "[" + value + "]", context); -// break; -// } -// case '|': -// case '~': -// case '<': -// case '>': -// case '!': -// input = input.substring(input.indexOf(char0) + 1); -// mask = parseFromInput(char0 + "[" + input + "]", context); -// if (actor != null) { -// actor.print(Caption.of("fawe.worldedit.help.command.clarifying.bracket", char0 + "[" + input + "]")); -// } -// return mask; -// } -// } -// } -// if (mask == null) { -// if (command.startsWith("[")) { -// int end = command.lastIndexOf(']'); -// mask = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context); -// } else { -// List entries = entry.getValue(); -// BlockMaskBuilder builder = new BlockMaskBuilder(); -//// if (StringMan.containsAny(full, "\\^$.|?+(){}<>~$!%^&*+-/")) -// { -// try { -// builder.addRegex(full); -// } catch (InputParseException ignored) {} -// } -// if (mask == null) { -// context.setPreferringWildcard(false); -// context.setRestricted(false); -// BaseBlock block = worldEdit.getBlockFactory().parseFromInput(full, context); -// builder.add(block); -// mask = builder.build(extent); -// } -// } -// } -// } -// if (pe.and) { -// masks.add(new ArrayList<>()); -// } -// masks.get(masks.size() - 1).add(mask); -// } -// } catch (InputParseException rethrow) { -// throw rethrow; -// } catch (Throwable e) { -// e.printStackTrace(); -// throw new InputParseException(e.getMessage(), e); -// } -// List maskUnions = new ArrayList<>(); -// for (List maskList : masks) { -// if (maskList.size() == 1) { -// maskUnions.add(maskList.get(0)); -// } else if (maskList.size() != 0) { -// maskUnions.add(new MaskUnion(maskList)); -// } -// } -// if (maskUnions.size() == 1) { -// return maskUnions.get(0); -// } else if (maskUnions.size() != 0) { -// return new MaskIntersection(maskUnions); -// } else { -// return null; -// } -// -// } -//} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java new file mode 100644 index 000000000..92f95c14f --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java @@ -0,0 +1,241 @@ +package com.fastasyncworldedit.core.extension.factory.parser.mask; + +import com.fastasyncworldedit.core.command.SuggestInputParseException; +import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extension.factory.parser.FaweParser; +import com.fastasyncworldedit.core.function.mask.BlockMaskBuilder; +import com.fastasyncworldedit.core.function.mask.MaskUnion; +import com.fastasyncworldedit.core.util.StringMan; +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.MaskIntersection; +import com.sk89q.worldedit.internal.command.CommandArgParser; +import com.sk89q.worldedit.internal.util.Substring; +import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.world.block.BaseBlock; +import org.enginehub.piston.inject.MemoizingValueAccess; +import org.enginehub.piston.suggestion.Suggestion; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Attempts to parse masks given rich inputs, allowing for & and ,. Also allows for nested masks + */ +public class RichMaskParser extends FaweParser { + + /** + * New instance + * + * @param worldEdit {@link WorldEdit} instance. + */ + public RichMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + if (input.isEmpty()) { + throw new SuggestInputParseException("No input provided", "", () -> Stream + .of("#", ",", "&") + .map(n -> n + ":") + .collect(Collectors.toList()) + // TODO namespaces + ); + } + Extent extent = context.getExtent(); + if (extent == null) { + extent = Request.request().getExtent(); + } + List> masks = new ArrayList<>(); + masks.add(new ArrayList<>()); + + final CommandLocals locals = new CommandLocals(); + Actor actor = context.getActor(); + if (actor != null) { + locals.put(Actor.class, actor); + } + try { + List>> parsed = parse(input); + for (Map.Entry> entry : parsed) { + ParseEntry pe = entry.getKey(); + final String command = pe.getInput(); + String full = pe.getFull(); + Mask mask = null; + if (command.isEmpty()) { + mask = parseFromInput(StringMan.join(entry.getValue(), ','), context); + } else if (!worldEdit.getMaskFactory().containsAlias(command)) { + // Legacy patterns + char char0 = command.charAt(0); + boolean charMask = input.length() > 1 && input.charAt(1) != '['; + if (charMask && input.charAt(0) == '=') { + return parseFromInput(char0 + "[" + input.substring(1) + "]", context); + } + if (char0 == '#') { + throw new SuggestInputParseException( + new NoMatchException(Caption.of("fawe.error.parse.unknown-mask", full, + TextComponent + .of("https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + ) + .clickEvent(ClickEvent.openUrl( + "https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + )) + )), + full, + () -> { + if (full.length() == 1) { + return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("")); + } + return new ArrayList<>(worldEdit + .getMaskFactory() + .getSuggestions(command.toLowerCase(Locale.ROOT))); + } + ); + } + // Legacy syntax + if (charMask) { + switch (char0) { + case '\\': // + case '/': // + case '{': // + case '$': // + case '%': { + String value = command.substring(1) + ((entry.getValue().isEmpty()) + ? "" + : "[" + StringMan.join( + entry.getValue(), + "][" + ) + "]"); + if (value.contains(":")) { + if (value.charAt(0) == ':') { + value = value.replaceFirst(":", ""); + } + value = value.replaceAll(":", "]["); + } + mask = parseFromInput("#" + char0 + "[" + value + "]", context); + break; + } + case '|': + case '~': + case '<': + case '>': + case '!': + input = input.substring(input.indexOf(char0) + 1); + mask = parseFromInput(char0 + "[" + input + "]", context); + if (actor != null) { + actor.print(Caption.of( + "fawe.worldedit.help.command.clarifying.bracket", + char0 + "[" + input + + "]" + )); + } + return mask; + } + } + if (mask == null) { + if (command.startsWith("[")) { + int end = command.lastIndexOf(']'); + mask = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context); + } else { + BlockMaskBuilder builder = new BlockMaskBuilder(); + try { + builder.addRegex(full); + } catch (InputParseException ignored) { + } + context.setPreferringWildcard(false); + context.setRestricted(false); + BaseBlock block = worldEdit.getBlockFactory().parseFromInput(full, context); + builder.add(block); + mask = builder.build(extent); + } + } + } else { + List args = entry.getValue(); + try { + mask = worldEdit.getMaskFactory().parseWithoutRich(full, context); + } catch (SuggestInputParseException rethrow) { + throw rethrow; + } catch (Throwable e) { + throw SuggestInputParseException.of(e, full, () -> { + try { + String cmdArgs = ((args.isEmpty()) ? "" : " " + StringMan.join(args, " ")); + List split = + CommandArgParser.forArgString(cmdArgs).parseArgs().collect(Collectors.toList()); + List argStrings = split + .stream() + .map(Substring::getSubstring) + .collect(Collectors.toList()); + MemoizingValueAccess access = getPlatform().initializeInjectedValues(() -> cmdArgs, + actor, + null, true + ); + List suggestions = getPlatform().getCommandManager().getSuggestions( + access, + argStrings + ).stream().map(Suggestion::getSuggestion).collect(Collectors.toUnmodifiableList()); + List result = new ArrayList<>(); + if (suggestions.size() <= 2) { + for (int i = 0; i < suggestions.size(); i++) { + String suggestion = suggestions.get(i); + if (suggestion.indexOf(' ') != 0) { + String[] splitSuggestion = suggestion.split(" "); + suggestion = "[" + StringMan.join(splitSuggestion, "][") + "]"; + result.set(i, suggestion); + } + } + } + return result; + } catch (Throwable e2) { + e2.printStackTrace(); + throw new InputParseException(Caption.of(e2.getMessage())); + } + }); + } + } + if (pe.isAnd()) { + masks.add(new ArrayList<>()); + } + masks.get(masks.size() - 1).add(mask); + } + } catch (InputParseException rethrow) { + throw rethrow; + } catch (Throwable e) { + e.printStackTrace(); + throw new InputParseException(Caption.of(e.getMessage()), e); + } + List maskUnions = new ArrayList<>(); + for (List maskList : masks) { + if (maskList.size() == 1) { + maskUnions.add(maskList.get(0)); + } else if (maskList.size() != 0) { + maskUnions.add(new MaskUnion(maskList)); + } + } + if (maskUnions.size() == 1) { + return maskUnions.get(0); + } else if (maskUnions.size() != 0) { + return new MaskIntersection(maskUnions); + } else { + return null; + } + } + + @Override + public List getMatchedAliases() { + return Collections.emptyList(); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AngleColorPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AngleColorPatternParser.java new file mode 100644 index 000000000..7074fdb13 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AngleColorPatternParser.java @@ -0,0 +1,47 @@ +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.AngleColorPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class AngleColorPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public AngleColorPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#anglecolor", "#anglecolour"); + } + + @Override + public Stream getSuggestions(String argumentInput, int index) { + if (index != 0) { + return Stream.empty(); + } + return SuggestionHelper.suggestPositiveIntegers(argumentInput); + } + + @Override + public Pattern parseFromInput(@Nonnull String[] input, ParserContext context) throws InputParseException { + if (input.length != 1) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[distance] (e.g. " + getPrefix() + "[10])") + )); + } + int distance = Integer.parseInt(input[0]); + return new AngleColorPattern(context.requireExtent(), context.requireSession(), distance); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AverageColorPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AverageColorPatternParser.java new file mode 100644 index 000000000..35d28382d --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AverageColorPatternParser.java @@ -0,0 +1,53 @@ +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.AverageColorPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class AverageColorPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public AverageColorPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#averagecolor", "#averagecolour"); + } + + @Override + public Stream getSuggestions(String argumentInput, int index) { + if (index > 4) { + return Stream.empty(); + } + return SuggestionHelper.suggestPositiveIntegers(argumentInput); + } + + @Override + public Pattern parseFromInput(@Nonnull String[] input, ParserContext context) throws InputParseException { + if (input.length != 4) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[r][g][b][a] (e.g. " + getPrefix() + "[156][100][0][120])") + )); + } + return new AverageColorPattern( + context.requireExtent(), + context.requireSession(), + Integer.parseInt(input[0]), + Integer.parseInt(input[1]), + Integer.parseInt(input[2]), + Integer.parseInt(input[3]) + ); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BiomePatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BiomePatternParser.java index 49ca52ab7..0adbe2cd7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BiomePatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BiomePatternParser.java @@ -25,7 +25,7 @@ public class BiomePatternParser extends RichParser { * @param worldEdit the worldedit instance. */ public BiomePatternParser(WorldEdit worldEdit) { - super(worldEdit, "#biome"); + super(worldEdit, "#biome", "$"); } // overridden to provide $ too diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java new file mode 100644 index 000000000..bd9f2a28c --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java @@ -0,0 +1,46 @@ +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.BufferedPattern2D; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class BufferedPattern2DParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public BufferedPattern2DParser(WorldEdit worldEdit) { + super(worldEdit, "#buffer2d"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + if (index == 0) { + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + public Pattern parseFromInput(@Nonnull String[] input, ParserContext context) throws InputParseException { + if (input.length != 1) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[pattern] (e.g. " + getPrefix() + "[stone,dirt])") + )); + } + Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(input[0], context); + return new BufferedPattern2D(context.requireActor(), inner); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ColorPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ColorPatternParser.java new file mode 100644 index 000000000..9b424d5eb --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ColorPatternParser.java @@ -0,0 +1,53 @@ +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.util.MathMan; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.awt.Color; +import java.util.stream.Stream; + +public class ColorPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public ColorPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#color", "#colour"); + } + + @Override + public Stream getSuggestions(String argumentInput, int index) { + if (index > 4) { + return Stream.empty(); + } + return SuggestionHelper.suggestPositiveIntegers(argumentInput); + } + + @Override + public Pattern parseFromInput(@Nonnull String[] input, ParserContext context) throws InputParseException { + if (input.length != 4) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[r][g][b][a] (e.g. " + getPrefix() + "[156][100][0][120])") + )); + } + Color color = new Color( + MathMan.clamp(Integer.parseInt(input[0]), 0, 255), + MathMan.clamp(Integer.parseInt(input[1]), 0, 255), + MathMan.clamp(Integer.parseInt(input[2]), 0, 255), + MathMan.clamp(Integer.parseInt(input[3]), 0, 255) + ); + return context.requireSession().getTextureUtil().getNearestBlock(color.getRGB()); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DarkenPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DarkenPatternParser.java new file mode 100644 index 000000000..c7eec6b6a --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DarkenPatternParser.java @@ -0,0 +1,36 @@ +package com.fastasyncworldedit.core.extension.factory.parser.pattern; + +import com.fastasyncworldedit.core.function.pattern.ShadePattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.registry.SimpleInputParser; + +import java.util.Collections; +import java.util.List; + +public class DarkenPatternParser extends SimpleInputParser { + + private final List aliases = Collections.singletonList("#darken"); + + /** + * Create a new simple parser with a defined prefix for the result. + * + * @param worldEdit the worldedit instance. + */ + public DarkenPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public List getMatchedAliases() { + return this.aliases; + } + + @Override + public Pattern parseFromSimpleInput(String input, ParserContext context) throws InputParseException { + return new ShadePattern(context.requireExtent(), context.requireSession(), true); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DefaultPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DefaultPatternParser.java deleted file mode 100644 index 60f8cc94d..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DefaultPatternParser.java +++ /dev/null @@ -1,167 +0,0 @@ -// TODO: Ping @MattBDev to reimplement (or remove because this class is stupid) 2020-02-04 -///* -//package com.fastasyncworldedit.core.extension.factory.parser.pattern; -// -//import com.boydti.fawe.command.FaweParser; -//import com.boydti.fawe.command.SuggestInputParseException; -//import com.boydti.fawe.object.random.TrueRandom; -//import com.boydti.fawe.util.StringMan; -//import com.google.common.collect.Iterables; -//import com.sk89q.minecraft.util.commands.CommandLocals; -//import com.sk89q.worldedit.WorldEdit; -//import com.sk89q.worldedit.extension.input.InputParseException; -//import com.sk89q.worldedit.extension.input.NoMatchException; -//import com.sk89q.worldedit.extension.input.ParserContext; -//import com.sk89q.worldedit.extension.platform.Actor; -//import com.sk89q.worldedit.extension.platform.PlatformCommandManager; -//import com.sk89q.worldedit.function.pattern.Pattern; -//import com.sk89q.worldedit.function.pattern.RandomPattern; -//import com.sk89q.worldedit.internal.expression.Expression; -//import com.sk89q.worldedit.world.block.BlockTypes; -// -//import java.util.ArrayList; -//import java.util.List; -//import java.util.Map; -//import java.util.stream.Collectors; -//import java.util.stream.Stream; -// -//public class DefaultPatternParser extends FaweParser { -// -// public DefaultPatternParser(WorldEdit worldEdit) { -// super(worldEdit, "patterns"); -// } -// -// @Override -// public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { -// if (input.isEmpty()) { -// throw new SuggestInputParseException("No input provided", "", () -> Stream.concat(Stream.of("#", ",", "&"), BlockTypes.getNameSpaces().stream().map(n -> n + ":")).collect(Collectors.toList())); -// } -// List chances = new ArrayList<>(); -// List patterns = new ArrayList<>(); -// final CommandLocals locals = new CommandLocals(); -// Actor actor = context != null ? context.getActor() : null; -// if (actor != null) { -// locals.put(Actor.class, actor); -// } -// try { -// for (Map.Entry> entry : parse(input)) { -// ParseEntry pe = entry.getKey(); -// final String command = pe.input; -// String full = pe.full; -// Pattern pattern = null; -// double chance = 1; -// if (command.isEmpty()) { -// pattern = parseFromInput(StringMan.join(entry.getValue(), ','), context); -// } else { -// List args = entry.getValue(); -// String cmdArgs = ((args.isEmpty()) ? "" : " " + StringMan.join(args, " ")); -// try { -// pattern = parse(command + cmdArgs, context); -// } catch (SuggestInputParseException rethrow) { -// throw rethrow; -// } catch (Throwable e) { -// // TODO NOT IMPLEMENTED -//// throw SuggestInputParseException.of(e, full, () -> { -//// try { -//// List suggestions = dispatcher.get(command).getCallable().getSuggestions(cmdArgs, locals); -//// if (suggestions.size() <= 2) { -//// for (int i = 0; i < suggestions.size(); i++) { -//// String suggestion = suggestions.get(i); -//// if (suggestion.indexOf(' ') != 0) { -//// String[] split = suggestion.split(" "); -//// suggestion = "[" + StringMan.join(split, "][") + "]"; -//// suggestions.set(i, suggestion); -//// } -//// } -//// } -//// return suggestions; -//// } catch (CommandException e1) { -//// throw new InputParseException(e1.getMessage()); -//// } catch (Throwable e2) { -//// e2.printStackTrace(); -//// throw new InputParseException(e2.getMessage()); -//// } -//// }); -// } -// if (pattern == null) { -// // Legacy patterns -// char char0 = command.charAt(0); -// boolean charMask = input.length() > 1 && input.charAt(1) != '['; -// if (charMask && input.charAt(0) == '=') { -// return parseFromInput(char0 + "[" + input.substring(1) + "]", context); -// } -// if (char0 == '#') { -// // TODO NOT IMPLEMENTED -//// throw new SuggestInputParseException(new NoMatchException("Unknown pattern: " + full + ", See: //patterns"), full, -//// () -> { -//// if (full.length() == 1) return new ArrayList<>(dispatcher.getPrimaryAliases()); -//// return dispatcher.getAliases().stream().filter( -//// s -> s.startsWith(command.toLowerCase(Locale.ROOT)) -//// ).collect(Collectors.toList()); -//// } -//// ); -// } -// -// -// if (charMask) { -// if (char0 == '$') { -// String value = command.substring(1) + ((entry.getValue().isEmpty()) ? "" -// : "[" + StringMan.join(entry.getValue(), "][") + "]"); -// if (value.contains(":")) { -// if (value.charAt(0) == ':') { -// value.replaceFirst(":", ""); -// } -// value = value.replaceAll(":", "]["); -// } -// pattern = parseFromInput(char0 + "[" + value + "]", context); -// } -// } -// if (pattern == null) { -// if (command.startsWith("[")) { -// int end = command.lastIndexOf(']'); -// pattern = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context); -// } else { -// int percentIndex = command.indexOf('%'); -// if (percentIndex != -1) { // Legacy percent pattern -// chance = Expression.compile(command.substring(0, percentIndex)).evaluate(); -// String value = command.substring(percentIndex + 1); -// if (!entry.getValue().isEmpty()) { -// if (!value.isEmpty()) value += " "; -// value += StringMan.join(entry.getValue(), " "); -// } -// pattern = parseFromInput(value, context); -// } else { // legacy block pattern -// try { -// pattern = worldEdit.getBlockFactory().parseFromInput(pe.full, context); -// } catch (NoMatchException e) { -// throw new NoMatchException(e.getMessage() + " See: //patterns"); -// } -// } -// } -// } -// } -// } -// if (pattern != null) { -// patterns.add(pattern); -// chances.add(chance); -// } -// } -// } catch (InputParseException rethrow) { -// throw rethrow; -// } catch (Throwable e) { -// e.printStackTrace(); -// throw new InputParseException(e.getMessage(), e); -// } -// if (patterns.isEmpty()) { -// return null; -// } -// if (patterns.size() == 1) { -// return patterns.get(0); -// } -// RandomPattern random = new RandomPattern(new TrueRandom()); -// for (int i = 0; i < patterns.size(); i++) { -// random.add(patterns.get(i), chances.get(i)); -// } -// return random; -// } -//} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DesaturatePatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DesaturatePatternParser.java new file mode 100644 index 000000000..2218f479e --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DesaturatePatternParser.java @@ -0,0 +1,46 @@ +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.DesaturatePattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class DesaturatePatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public DesaturatePatternParser(WorldEdit worldEdit) { + super(worldEdit, "#desaturate"); + } + + @Override + public Stream getSuggestions(String argumentInput, int index) { + if (index == 0) { + return SuggestionHelper.suggestPositiveDoubles(argumentInput); + } + return Stream.empty(); + } + + @Override + public Pattern parseFromInput(@Nonnull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length != 1) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[percent] (e.g. " + getPrefix() + "[90])") + )); + } + return new DesaturatePattern(context.requireExtent(), context.requireSession(), Double.parseDouble(arguments[0]) / 100); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ExistingPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ExistingPatternParser.java index f77bdd287..70fc07c59 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ExistingPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ExistingPatternParser.java @@ -14,6 +14,11 @@ public class ExistingPatternParser extends SimpleInputParser { private final List aliases = Collections.singletonList("#existing"); + /** + * Create a new simple parser with a defined prefix for the result. + * + * @param worldEdit the worldedit instance. + */ public ExistingPatternParser(WorldEdit worldEdit) { super(worldEdit); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ExpressionPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ExpressionPatternParser.java new file mode 100644 index 000000000..42302235f --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ExpressionPatternParser.java @@ -0,0 +1,53 @@ +package com.fastasyncworldedit.core.extension.factory.parser.pattern; + +import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.function.pattern.ExpressionPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.internal.registry.SimpleInputParser; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import java.util.Collections; +import java.util.List; + +public class ExpressionPatternParser extends SimpleInputParser { + + private final List aliases = Collections.singletonList("="); + + /** + * Create a new simple parser with a defined prefix for the result. + * + * @param worldEdit the worldedit instance. + */ + public ExpressionPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public List getMatchedAliases() { + return this.aliases; + } + + @Override + public Pattern parseFromSimpleInput(String input, ParserContext context) throws InputParseException { + try { + Expression exp = Expression.compile(input.substring(1), "x", "y", "z"); + WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment( + context.requireExtent(), Vector3.ONE, Vector3.ZERO); + exp.setEnvironment(env); + return new ExpressionPattern(exp); + } catch (ExpressionException e) { + throw new InputParseException(Caption.of( + "worldedit.error.parser.invalid-expression", + TextComponent.of(e.getMessage()) + )); + } + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LightenPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LightenPatternParser.java new file mode 100644 index 000000000..4c9e9e42f --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LightenPatternParser.java @@ -0,0 +1,36 @@ +package com.fastasyncworldedit.core.extension.factory.parser.pattern; + +import com.fastasyncworldedit.core.function.pattern.ShadePattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.registry.SimpleInputParser; + +import java.util.Collections; +import java.util.List; + +public class LightenPatternParser extends SimpleInputParser { + + private final List aliases = Collections.singletonList("#lighten"); + + /** + * Create a new simple parser with a defined prefix for the result. + * + * @param worldEdit the worldedit instance. + */ + public LightenPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public List getMatchedAliases() { + return this.aliases; + } + + @Override + public Pattern parseFromSimpleInput(String input, ParserContext context) throws InputParseException { + return new ShadePattern(context.requireExtent(), context.requireSession(), false); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LinearPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LinearPatternParser.java new file mode 100644 index 000000000..7d7813c4a --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LinearPatternParser.java @@ -0,0 +1,64 @@ +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.LinearBlockPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.RandomPattern; +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 LinearPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public LinearPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#linear", "#l"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + switch (index) { + case 0: + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 1: + case 2: + case 3: + return SuggestionHelper.suggestPositiveIntegers(argumentInput); + default: + return Stream.empty(); + } + } + + @Override + protected Pattern parseFromInput(@Nonnull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length != 1) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[pattern] (e.g. " + getPrefix() + "[stone,dirt])") + )); + } + Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(arguments[0], context); + if (inner instanceof BlockStateHolder) { + return inner; + } + if (inner instanceof RandomPattern) { + Set patterns = ((RandomPattern) inner).getPatterns(); + return new LinearBlockPattern(patterns.toArray(new Pattern[0])); + } + throw new InputParseException(Caption.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/MaskedPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/MaskedPatternParser.java new file mode 100644 index 000000000..426754675 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/MaskedPatternParser.java @@ -0,0 +1,54 @@ +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.MaskedPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class MaskedPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public MaskedPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#mask"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + switch (index) { + case 0: + return this.worldEdit.getMaskFactory().getSuggestions(argumentInput).stream(); + case 1: + case 2: + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + default: + return Stream.empty(); + } + } + + @Override + protected Pattern parseFromInput(@Nonnull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length != 3) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[mask][pattern][pattern] (e.g. " + getPrefix() + "[oak_planks][dirt][stone])") + )); + } + Mask mask = this.worldEdit.getMaskFactory().parseFromInput(arguments[0], context); + Pattern inner1 = this.worldEdit.getPatternFactory().parseFromInput(arguments[1], context); + Pattern inner2 = this.worldEdit.getPatternFactory().parseFromInput(arguments[2], context); + return new MaskedPattern(mask, inner1, inner2); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoXPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoXPatternParser.java new file mode 100644 index 000000000..8e3ac729f --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoXPatternParser.java @@ -0,0 +1,46 @@ +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.NoXPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class NoXPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public NoXPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#!x", "#nx", "#nox"); + } + + @Override + public Stream getSuggestions(String argumentInput, int index) { + if (index == 0) { + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + public Pattern parseFromInput(@Nonnull String[] input, ParserContext context) throws InputParseException { + if (input.length != 1) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[pattern] (e.g. " + getPrefix() + "[stone,dirt])") + )); + } + Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(input[0], context); + return new NoXPattern(inner); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoYPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoYPatternParser.java new file mode 100644 index 000000000..2cc00c8ad --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoYPatternParser.java @@ -0,0 +1,46 @@ +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.NoYPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class NoYPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public NoYPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#!y", "#ny", "#noy"); + } + + @Override + public Stream getSuggestions(String argumentInput, int index) { + if (index == 0) { + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + public Pattern parseFromInput(@Nonnull String[] input, ParserContext context) throws InputParseException { + if (input.length != 1) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[pattern] (e.g. " + getPrefix() + "[stone,dirt])") + )); + } + Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(input[0], context); + return new NoYPattern(inner); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoZPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoZPatternParser.java new file mode 100644 index 000000000..927d13d0c --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoZPatternParser.java @@ -0,0 +1,46 @@ +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.NoZPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class NoZPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public NoZPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#!z", "#nz", "#noz"); + } + + @Override + public Stream getSuggestions(String argumentInput, int index) { + if (index == 0) { + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + public Pattern parseFromInput(@Nonnull String[] input, ParserContext context) throws InputParseException { + if (input.length != 1) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[pattern] (e.g. " + getPrefix() + "[stone,dirt])") + )); + } + Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(input[0], context); + return new NoZPattern(inner); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/OffsetPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/OffsetPatternParser.java new file mode 100644 index 000000000..d7adf2c6b --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/OffsetPatternParser.java @@ -0,0 +1,67 @@ +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.OffsetPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class OffsetPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public OffsetPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#offset"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + switch (index) { + case 0: + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 1: + case 2: + case 3: + return SuggestionHelper.suggestPositiveIntegers(argumentInput); + default: + return Stream.empty(); + } + } + + @Override + protected Pattern parseFromInput(@Nonnull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length != 2 && arguments.length != 4) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[pattern] (e.g. " + getPrefix() + "[stone][2][0][4])") + )); + } + int x; + int y; + int z; + Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(arguments[0], context); + if (arguments.length == 4) { + x = Integer.parseInt(arguments[1]); + y = Integer.parseInt(arguments[2]); + z = Integer.parseInt(arguments[3]); + } else { + x = y = z = Integer.parseInt(arguments[1]); + } + Extent extent = context.requireExtent(); + int minY = extent.getMinY(); + int maxY = extent.getMaxY(); + return new OffsetPattern(inner, x, y, z, minY, maxY); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomFullClipboardPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomFullClipboardPatternParser.java new file mode 100644 index 000000000..a0ebadc6a --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomFullClipboardPatternParser.java @@ -0,0 +1,93 @@ +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.extent.clipboard.MultiClipboardHolder; +import com.fastasyncworldedit.core.function.pattern.RandomFullClipboardPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +public class RandomFullClipboardPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public RandomFullClipboardPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#fullcopy"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + switch (index) { + case 1: + case 2: + return SuggestionHelper.suggestBoolean(argumentInput); + default: + return Stream.empty(); + } + } + + @Override + protected Pattern parseFromInput(@Nonnull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length == 0 || arguments.length > 3) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[pattern] (e.g. " + getPrefix() + "[#copy][true][false])") + )); + } + try { + boolean rotate = arguments.length >= 2 && Boolean.getBoolean(arguments[1]); + boolean flip = arguments.length == 3 && Boolean.getBoolean(arguments[2]); + List clipboards; + switch (arguments[0].toLowerCase()) { + case "#copy": + case "#clipboard": + ClipboardHolder clipboard = context.requireSession().getExistingClipboard(); + if (clipboard == null) { + throw new InputParseException(Caption.of("fawe.error.parse.no-clipboard", getPrefix())); + } + clipboards = Collections.singletonList(clipboard); + break; + default: + Actor player = context.requireActor(); + MultiClipboardHolder multi = ClipboardFormats.loadAllFromInput(player, + arguments[0], ClipboardFormats.findByAlias("fast"), true + ); + if (multi == null) { + multi = ClipboardFormats.loadAllFromInput(player, + arguments[0], ClipboardFormats.findByAlias("sponge"), true + ); + } + if (multi == null) { + multi = ClipboardFormats.loadAllFromInput(player, + arguments[0], ClipboardFormats.findByAlias("mcedit"), true + ); + } + if (multi == null) { + throw new InputParseException(Caption.of("fawe.error.parse.no-clipboard-source", arguments[0])); + } + clipboards = multi.getHolders(); + break; + } + return new RandomFullClipboardPattern(clipboards, rotate, flip); + } catch (IOException e) { + throw new InputParseException(Caption.of(e.getMessage()), e); + } + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomOffsetPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomOffsetPatternParser.java new file mode 100644 index 000000000..e3efcf6e3 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomOffsetPatternParser.java @@ -0,0 +1,65 @@ +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.RandomOffsetPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class RandomOffsetPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public RandomOffsetPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#spread", "#randomoffset"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + switch (index) { + case 0: + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 1: + case 2: + case 3: + return SuggestionHelper.suggestPositiveIntegers(argumentInput); + default: + return Stream.empty(); + } + } + + @Override + protected Pattern parseFromInput(@Nonnull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length != 2 && arguments.length != 4) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[pattern] (e.g. " + getPrefix() + "[stone][2][0][4])") + )); + } + int x; + int y; + int z; + Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(arguments[0], context); + if (arguments.length == 4) { + x = Integer.parseInt(arguments[1]); + y = Integer.parseInt(arguments[2]); + z = Integer.parseInt(arguments[3]); + } else { + x = y = z = Integer.parseInt(arguments[1]); + } + Extent extent = context.requireExtent(); + return new RandomOffsetPattern(inner, x, y, z, extent.getMinY(), extent.getMaxY()); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomPatternParser.java index 6908f49e7..f617d0e63 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomPatternParser.java @@ -15,6 +15,11 @@ import java.util.stream.Stream; public class RandomPatternParser extends InputParser { + /** + * Create a new input parser. + * + * @param worldEdit the worldedit instance. + */ public RandomPatternParser(WorldEdit worldEdit) { super(worldEdit); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RelativePatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RelativePatternParser.java new file mode 100644 index 000000000..e998a6db9 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RelativePatternParser.java @@ -0,0 +1,48 @@ +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.RelativePattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class RelativePatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public RelativePatternParser(WorldEdit worldEdit) { + super(worldEdit, "#relative", "#~", "#r", "#rel"); + } + + @Override + public Stream getSuggestions(String argumentInput, int index) { + if (index == 0) { + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + public Pattern parseFromInput(@Nonnull String[] input, ParserContext context) throws InputParseException { + if (input.length != 1) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[pattern] (e.g. " + getPrefix() + "[stone,dirt])") + )); + } + Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(input[0], context); + Extent extent = context.requireExtent(); + return new RelativePattern(inner, extent.getMinY(), extent.getMaxY()); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RichPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RichPatternParser.java new file mode 100644 index 000000000..49466e8ee --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RichPatternParser.java @@ -0,0 +1,211 @@ +package com.fastasyncworldedit.core.extension.factory.parser.pattern; + +import com.fastasyncworldedit.core.command.SuggestInputParseException; +import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extension.factory.parser.FaweParser; +import com.fastasyncworldedit.core.math.random.TrueRandom; +import com.fastasyncworldedit.core.util.StringMan; +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.RandomPattern; +import com.sk89q.worldedit.internal.command.CommandArgParser; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.util.Substring; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.world.block.BlockTypes; +import org.enginehub.piston.inject.MemoizingValueAccess; +import org.enginehub.piston.suggestion.Suggestion; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class RichPatternParser extends FaweParser { + + /** + * Create a new rich pattern-parser. + * + * @param worldEdit the worldedit instance. + */ + public RichPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + if (input.isEmpty()) { + throw new SuggestInputParseException( + "No input provided", + "", + () -> Stream + .concat(Stream.of("#", ",", "&"), BlockTypes.getNameSpaces().stream().map(n -> n + ":")) + .collect(Collectors.toList()) + ); + } + List chances = new ArrayList<>(); + List patterns = new ArrayList<>(); + final CommandLocals locals = new CommandLocals(); + Actor actor = context != null ? context.getActor() : null; + if (actor != null) { + locals.put(Actor.class, actor); + } + try { + for (Map.Entry> entry : parse(input)) { + ParseEntry pe = entry.getKey(); + final String command = pe.getInput(); + String full = pe.getFull(); + Pattern pattern = null; + double chance = 1; + if (command.isEmpty()) { + pattern = parseFromInput(StringMan.join(entry.getValue(), ','), context); + } else if (!worldEdit.getPatternFactory().containsAlias(command)) { + // Legacy patterns + char char0 = command.charAt(0); + boolean charPattern = input.length() > 1 && input.charAt(1) != '['; + if (charPattern && input.charAt(0) == '=') { + return parseFromInput(char0 + "[" + input.substring(1) + "]", context); + } + if (char0 == '#' && command.length() > 1 && command.charAt(1) != '#') { + throw new SuggestInputParseException( + new NoMatchException(Caption.of("fawe.error.parse.unknown-pattern", full, + TextComponent + .of("https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + ) + .clickEvent( + ClickEvent.openUrl( + "https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + )) + )), + full, + () -> { + if (full.length() == 1) { + return new ArrayList<>(worldEdit.getPatternFactory().getSuggestions("")); + } + return new ArrayList<>(worldEdit + .getPatternFactory() + .getSuggestions(command.toLowerCase(Locale.ROOT))); + } + ); + } + + if (charPattern) { + if (char0 == '$' || char0 == '^' || char0 == '*' || (char0 == '#' && input.charAt(1) == '#')) { + pattern = worldEdit.getPatternFactory().parseWithoutRich(full, context); + } + } + if (pattern == null) { + if (command.startsWith("[")) { + int end = command.lastIndexOf(']'); + pattern = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context); + } else { + int percentIndex = command.indexOf('%'); + if (percentIndex != -1) { // Legacy percent pattern + chance = Expression.compile(command.substring(0, percentIndex)).evaluate(); + String value = command.substring(percentIndex + 1); + if (!entry.getValue().isEmpty()) { + if (!value.isEmpty()) { + value += " "; + } + value += StringMan.join(entry.getValue(), " "); + } + pattern = parseFromInput(value, context); + } else { // legacy block pattern + try { + pattern = worldEdit.getBlockFactory().parseFromInput(pe.getFull(), context); + } catch (NoMatchException e) { + throw new NoMatchException(Caption.of("fawe.error.parse.unknown-pattern", full, + TextComponent + .of("https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + ) + .clickEvent( + com.sk89q.worldedit.util.formatting.text.event.ClickEvent.openUrl( + "https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + )) + )); + } + } + } + } + } else { + List args = entry.getValue(); + try { + pattern = worldEdit.getPatternFactory().parseWithoutRich(full, context); + } catch (SuggestInputParseException rethrow) { + throw rethrow; + } catch (Throwable e) { + throw SuggestInputParseException.of(e, full, () -> { + try { + String cmdArgs = ((args.isEmpty()) ? "" : " " + StringMan.join(args, " ")); + List split = + CommandArgParser.forArgString(cmdArgs).parseArgs().collect(Collectors.toList()); + List argStrings = split + .stream() + .map(Substring::getSubstring) + .collect(Collectors.toList()); + MemoizingValueAccess access = getPlatform().initializeInjectedValues(() -> cmdArgs, + actor, + null, true + ); + List suggestions = getPlatform().getCommandManager().getSuggestions( + access, + argStrings + ).stream().map(Suggestion::getSuggestion).collect(Collectors.toUnmodifiableList()); + List result = new ArrayList<>(); + if (suggestions.size() <= 2) { + for (int i = 0; i < suggestions.size(); i++) { + String suggestion = suggestions.get(i); + if (suggestion.indexOf(' ') != 0) { + String[] splitSuggestion = suggestion.split(" "); + suggestion = "[" + StringMan.join(splitSuggestion, "][") + "]"; + result.set(i, suggestion); + } + } + } + return result; + } catch (Throwable e2) { + e2.printStackTrace(); + throw new InputParseException(Caption.of(e2.getMessage())); + } + }); + } + } + if (pattern != null) { + patterns.add(pattern); + chances.add(chance); + } + } + } catch (InputParseException rethrow) { + throw rethrow; + } catch (Throwable e) { + e.printStackTrace(); + throw new InputParseException(Caption.of(e.getMessage()), e); + } + if (patterns.isEmpty()) { + return null; + } + if (patterns.size() == 1) { + return patterns.get(0); + } + RandomPattern random = new RandomPattern(new TrueRandom()); + for (int i = 0; i < patterns.size(); i++) { + random.add(patterns.get(i), chances.get(i)); + } + return random; + } + + @Override + public List getMatchedAliases() { + return Collections.emptyList(); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SaturatePatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SaturatePatternParser.java new file mode 100644 index 000000000..bb40f029d --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SaturatePatternParser.java @@ -0,0 +1,51 @@ +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.SaturatePattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class SaturatePatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public SaturatePatternParser(WorldEdit worldEdit) { + super(worldEdit, "#saturate"); + } + + @Override + public Stream getSuggestions(String argumentInput, int index) { + if (index > 3) { + return Stream.empty(); + } + return SuggestionHelper.suggestPositiveIntegers(argumentInput); + } + + @Override + public Pattern parseFromInput(@Nonnull String[] input, ParserContext context) throws InputParseException { + if (input.length != 4) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[r][g][b][a] (e.g. " + getPrefix() + "[156][100][0][120])") + )); + } + return new SaturatePattern(context.requireExtent(), context.requireSession(), + Integer.parseInt(input[0]), + Integer.parseInt(input[1]), + Integer.parseInt(input[2]), + Integer.parseInt(input[3]) + ); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SimplexPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SimplexPatternParser.java index 6bf4dd123..44a565867 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SimplexPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SimplexPatternParser.java @@ -7,6 +7,11 @@ public class SimplexPatternParser extends NoisePatternParser { private static final String SIMPLEX_NAME = "simplex"; + /** + * Create a new rich pattern parser with a defined prefix for the result. + * + * @param worldEdit the worldedit instance. + */ public SimplexPatternParser(WorldEdit worldEdit) { super(worldEdit, SIMPLEX_NAME, SimplexNoiseGenerator::new); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SolidRandomOffsetPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SolidRandomOffsetPatternParser.java new file mode 100644 index 000000000..bd8115ea7 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SolidRandomOffsetPatternParser.java @@ -0,0 +1,65 @@ +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.SolidRandomOffsetPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class SolidRandomOffsetPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public SolidRandomOffsetPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#solidspread"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + switch (index) { + case 0: + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 1: + case 2: + case 3: + return SuggestionHelper.suggestPositiveIntegers(argumentInput); + default: + return Stream.empty(); + } + } + + @Override + protected Pattern parseFromInput(@Nonnull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length != 2 && arguments.length != 4) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[pattern] (e.g. " + getPrefix() + "[stone][2][0][4])") + )); + } + int x; + int y; + int z; + Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(arguments[0], context); + if (arguments.length == 4) { + x = Integer.parseInt(arguments[1]); + y = Integer.parseInt(arguments[2]); + z = Integer.parseInt(arguments[3]); + } else { + x = y = z = Integer.parseInt(arguments[1]); + } + Extent extent = context.requireExtent(); + return new SolidRandomOffsetPattern(inner, x, y, z, extent.getMinY(), extent.getMaxY()); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SurfaceRandomOffsetPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SurfaceRandomOffsetPatternParser.java new file mode 100644 index 000000000..50c100e80 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SurfaceRandomOffsetPatternParser.java @@ -0,0 +1,54 @@ +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.SurfaceRandomOffsetPattern; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class SurfaceRandomOffsetPatternParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public SurfaceRandomOffsetPatternParser(WorldEdit worldEdit) { + super(worldEdit, "#surfacespread"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + switch (index) { + case 0: + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 1: + return SuggestionHelper.suggestPositiveIntegers(argumentInput); + default: + return Stream.empty(); + } + } + + @Override + protected Pattern parseFromInput(@Nonnull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length != 2) { + throw new InputParseException(Caption.of( + "fawe.error.command.syntax", + TextComponent.of(getPrefix() + "[pattern] (e.g. " + getPrefix() + "[stone][2])") + )); + } + Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(arguments[0], context); + int distance = Integer.parseInt(arguments[1]); + Extent extent = context.requireExtent(); + return new SurfaceRandomOffsetPattern(inner, distance, extent.getMinY(), extent.getMaxY()); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/Linear3DTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/Linear3DTransformParser.java new file mode 100644 index 000000000..bfd68c7cf --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/Linear3DTransformParser.java @@ -0,0 +1,45 @@ +package com.fastasyncworldedit.core.extension.factory.parser.transform; + +import com.fastasyncworldedit.core.extension.factory.parser.RichParser; +import com.fastasyncworldedit.core.extent.ResettableExtent; +import com.fastasyncworldedit.core.extent.transform.Linear3DTransform; +import com.fastasyncworldedit.core.extent.transform.RandomTransform; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import org.jetbrains.annotations.NotNull; + +import java.util.stream.Stream; + +public class Linear3DTransformParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public Linear3DTransformParser(WorldEdit worldEdit) { + super(worldEdit, "#linear3d", "#l3d"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + if (index == 0) { + return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + protected ResettableExtent parseFromInput(@NotNull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length != 1) { + return null; + } + ResettableExtent inner = worldEdit.getTransformFactory().parseFromInput(arguments[0], context); + if (inner instanceof RandomTransform) { + return new Linear3DTransform(((RandomTransform) inner).getExtents().toArray(new ResettableExtent[0])); + } + return inner; // TODO what about non-random transforms? + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/LinearTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/LinearTransformParser.java new file mode 100644 index 000000000..3a09669b2 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/LinearTransformParser.java @@ -0,0 +1,45 @@ +package com.fastasyncworldedit.core.extension.factory.parser.transform; + +import com.fastasyncworldedit.core.extension.factory.parser.RichParser; +import com.fastasyncworldedit.core.extent.ResettableExtent; +import com.fastasyncworldedit.core.extent.transform.LinearTransform; +import com.fastasyncworldedit.core.extent.transform.RandomTransform; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import org.jetbrains.annotations.NotNull; + +import java.util.stream.Stream; + +public class LinearTransformParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public LinearTransformParser(WorldEdit worldEdit) { + super(worldEdit, "#linear", "#l"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + if (index == 0) { + return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + protected ResettableExtent parseFromInput(@NotNull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length != 1) { + return null; + } + ResettableExtent inner = worldEdit.getTransformFactory().parseFromInput(arguments[0], context); + if (inner instanceof RandomTransform) { + return new LinearTransform(((RandomTransform) inner).getExtents().toArray(new ResettableExtent[0])); + } + return inner; // TODO what about non-random transforms? + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/OffsetTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/OffsetTransformParser.java new file mode 100644 index 000000000..f5fe4f70b --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/OffsetTransformParser.java @@ -0,0 +1,55 @@ +package com.fastasyncworldedit.core.extension.factory.parser.transform; + +import com.fastasyncworldedit.core.extension.factory.parser.RichParser; +import com.fastasyncworldedit.core.extent.transform.OffsetTransform; +import com.fastasyncworldedit.core.extent.ResettableExtent; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import org.jetbrains.annotations.NotNull; + +import java.util.stream.Stream; + +public class OffsetTransformParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public OffsetTransformParser(WorldEdit worldEdit) { + super(worldEdit, "#offset"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + if (index < 3) { + return SuggestionHelper.suggestPositiveIntegers(argumentInput); + } else if (index == 3) { + return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + protected ResettableExtent parseFromInput(@NotNull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length != 3 && arguments.length != 4) { + throw new InputParseException(TranslatableComponent.of( + "fawe.error.command.syntax", + TextComponent.of("#offset[x][y][z]") + )); + } + int xOffset = Integer.parseInt(arguments[0]); + int yOffset = Integer.parseInt(arguments[1]); + int zOffset = Integer.parseInt(arguments[2]); + Extent extent; + extent = arguments.length == 4 ? worldEdit.getTransformFactory().parseFromInput(arguments[3], context) : + context.requireExtent(); + return new OffsetTransform(extent, xOffset, yOffset, zOffset); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/PatternTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/PatternTransformParser.java new file mode 100644 index 000000000..c1ecd7a50 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/PatternTransformParser.java @@ -0,0 +1,47 @@ +package com.fastasyncworldedit.core.extension.factory.parser.transform; + +import com.fastasyncworldedit.core.extension.factory.parser.RichParser; +import com.fastasyncworldedit.core.extent.ResettableExtent; +import com.fastasyncworldedit.core.extent.transform.PatternTransform; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; +import org.jetbrains.annotations.NotNull; + +import java.util.stream.Stream; + +public class PatternTransformParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public PatternTransformParser(WorldEdit worldEdit) { + super(worldEdit, "#pattern"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + if (index == 0) { + return worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + } else if (index == 1) { + return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + protected ResettableExtent parseFromInput(@NotNull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length > 2) { + return null; + } + Pattern pattern = worldEdit.getPatternFactory().parseFromInput(arguments[0], context); + Extent extent = arguments.length == 2 ? worldEdit.getTransformFactory().parseFromInput(arguments[1], context) : + context.requireExtent(); + return new PatternTransform(extent, pattern); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RandomTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RandomTransformParser.java new file mode 100644 index 000000000..b21834812 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RandomTransformParser.java @@ -0,0 +1,60 @@ +package com.fastasyncworldedit.core.extension.factory.parser.transform; + +import com.fastasyncworldedit.core.extent.ResettableExtent; +import com.fastasyncworldedit.core.extent.transform.RandomTransform; +import com.sk89q.util.StringUtil; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.internal.registry.InputParser; + +import java.util.List; +import java.util.stream.Stream; + +public class RandomTransformParser extends InputParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public RandomTransformParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.empty(); + } + List split = StringUtil.split(input, ',', '[', ']'); + if (split.size() == 1) { + return Stream.empty(); + } + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < split.size() - 1; i++) { + builder.append(split.get(i)).append(','); + } + String previous = builder.toString(); + return worldEdit.getTransformFactory().getSuggestions(split.get(split.size() - 1)).stream() + .map(s -> previous + s); + } + + @Override + public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException { + if (input.isEmpty()) { + return null; + } + List split = StringUtil.split(input, ',', '[', ']'); + if (split.size() == 1) { + return null; + } + RandomTransform randomTransform = new RandomTransform(); + for (int i = 0; i < split.size(); i++) { + ResettableExtent transform = worldEdit.getTransformFactory().parseFromInput(split.get(i), context); + randomTransform.add(transform, 1d); + } + return randomTransform; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RichTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RichTransformParser.java new file mode 100644 index 000000000..628c60e09 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RichTransformParser.java @@ -0,0 +1,170 @@ +package com.fastasyncworldedit.core.extension.factory.parser.transform; + +import com.fastasyncworldedit.core.command.SuggestInputParseException; +import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extension.factory.parser.FaweParser; +import com.fastasyncworldedit.core.extent.ResettableExtent; +import com.fastasyncworldedit.core.extent.transform.MultiTransform; +import com.fastasyncworldedit.core.extent.transform.RandomTransform; +import com.fastasyncworldedit.core.math.random.TrueRandom; +import com.fastasyncworldedit.core.util.StringMan; +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Attempts to parse transforms given rich inputs, allowing for & and ,. Also allows for nested transforms + */ +public class RichTransformParser extends FaweParser { + + /** + * New instance + * + * @param worldEdit {@link WorldEdit} instance. + */ + public RichTransformParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException { + if (input.isEmpty()) { + return null; + } + + List unionChances = new ArrayList<>(); + List intersectionChances = new ArrayList<>(); + + List intersection = new ArrayList<>(); + List union = new ArrayList<>(); + final CommandLocals locals = new CommandLocals(); + Actor actor = context != null ? context.getActor() : null; + if (actor != null) { + locals.put(Actor.class, actor); + } + try { + List>> parsed = parse(input); + for (Map.Entry> entry : parsed) { + ParseEntry pe = entry.getKey(); + String command = pe.getInput(); + ResettableExtent transform; + double chance = 1; + if (command.isEmpty()) { + transform = parseFromInput(StringMan.join(entry.getValue(), ','), context); + } else if (!worldEdit.getTransformFactory().containsAlias(command)) { + // Legacy syntax + int percentIndex = command.indexOf('%'); + if (percentIndex != -1) { // Legacy percent pattern + chance = Expression.compile(command.substring(0, percentIndex)).evaluate(); + command = command.substring(percentIndex + 1); + if (!entry.getValue().isEmpty()) { + if (!command.isEmpty()) { + command += " "; + } + command += StringMan.join(entry.getValue(), " "); + } + transform = parseFromInput(command, context); + } else { + throw new NoMatchException(Caption.of("fawe.error.parse.unknown-transform", pe.getFull(), + TextComponent + .of("https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + ) + .clickEvent(ClickEvent.openUrl( + "https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + )) + )); + } + } else { + try { + transform = worldEdit.getTransformFactory().parseWithoutRich(pe.getFull(), context); + } catch (SuggestInputParseException rethrow) { + throw rethrow; + } catch (Throwable e) { + throw new NoMatchException(Caption.of("fawe.error.parse.unknown-transform", pe.getFull(), + TextComponent + .of("https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + ) + .clickEvent(ClickEvent.openUrl( + "https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + )) + )); + } + } + if (pe.isAnd()) { // & + intersectionChances.add(chance); + intersection.add(transform); + } else { + if (!intersection.isEmpty()) { + if (intersection.size() == 1) { + throw new InputParseException(Caption.of("fawe.error.parse.invalid-dangling-character", "&")); + } + MultiTransform multi = new MultiTransform(); + double total = 0; + for (int i = 0; i < intersection.size(); i++) { + Double value = intersectionChances.get(i); + total += value; + multi.add(intersection.get(i), value); + } + union.add(multi); + unionChances.add(total); + intersection.clear(); + intersectionChances.clear(); + } + unionChances.add(chance); + union.add(transform); + } + } + } catch (Throwable e) { + throw new InputParseException(Caption.of(e.getMessage()), e); + } + if (!intersection.isEmpty()) { + if (intersection.size() == 1) { + throw new InputParseException(Caption.of("fawe.error.parse.invalid-dangling-character", "&")); + } + MultiTransform multi = new MultiTransform(); + double total = 0; + for (int i = 0; i < intersection.size(); i++) { + Double value = intersectionChances.get(i); + total += value; + multi.add(intersection.get(i), value); + } + union.add(multi); + unionChances.add(total); + intersection.clear(); + intersectionChances.clear(); + } + if (union.isEmpty()) { + throw new NoMatchException(Caption.of("fawe.error.parse.unknown-transform", input, + TextComponent.of("https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + ).clickEvent(ClickEvent.openUrl( + "https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki/Transforms" + )) + )); + } else if (union.size() == 1) { + return union.get(0); + } else { + RandomTransform random = new RandomTransform(new TrueRandom()); + for (int i = 0; i < union.size(); i++) { + random.add(union.get(i), unionChances.get(i)); + } + return random; + } + } + + @Override + public List getMatchedAliases() { + return Collections.emptyList(); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RotateTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RotateTransformParser.java new file mode 100644 index 000000000..f82328e14 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RotateTransformParser.java @@ -0,0 +1,57 @@ +package com.fastasyncworldedit.core.extension.factory.parser.transform; + +import com.fastasyncworldedit.core.extension.factory.parser.RichParser; +import com.fastasyncworldedit.core.extent.ResettableExtent; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.transform.BlockTransformExtent; +import com.sk89q.worldedit.math.transform.AffineTransform; +import org.jetbrains.annotations.NotNull; + +import java.util.stream.Stream; + +public class RotateTransformParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public RotateTransformParser(WorldEdit worldEdit) { + super(worldEdit, "#rotate"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + if (index < 3) { + return SuggestionHelper.suggestPositiveDoubles(argumentInput); + } + if (index == 3) { + return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + protected ResettableExtent parseFromInput(@NotNull String[] arguments, ParserContext context) throws InputParseException { + AffineTransform transform = new AffineTransform(); + Extent extent; + if (arguments.length == 1) { + transform = transform.rotateY(Double.parseDouble(arguments[0])); + extent = context.requireExtent(); + } else if (arguments.length == 3 || arguments.length == 4) { + transform = transform.rotateX(Double.parseDouble(arguments[0])); + transform = transform.rotateY(Double.parseDouble(arguments[1])); + transform = transform.rotateZ(Double.parseDouble(arguments[2])); + extent = arguments.length == 4 ? worldEdit.getTransformFactory().parseFromInput(arguments[3], context) : + context.requireExtent(); + } else { + return null; + } + return new BlockTransformExtent(extent, transform); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/ScaleTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/ScaleTransformParser.java new file mode 100644 index 000000000..856be56ff --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/ScaleTransformParser.java @@ -0,0 +1,57 @@ +package com.fastasyncworldedit.core.extension.factory.parser.transform; + +import com.fastasyncworldedit.core.extension.factory.parser.RichParser; +import com.fastasyncworldedit.core.extent.ResettableExtent; +import com.fastasyncworldedit.core.extent.transform.ScaleTransform; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import org.jetbrains.annotations.NotNull; + +import java.util.stream.Stream; + +public class ScaleTransformParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #scale}. + * + * @param worldEdit the worldedit instance. + */ + public ScaleTransformParser(WorldEdit worldEdit) { + super(worldEdit, "#scale"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + if (index < 3) { + return SuggestionHelper.suggestPositiveDoubles(argumentInput); + } else if (index == 3) { + return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + protected ResettableExtent parseFromInput(@NotNull String[] arguments, ParserContext context) throws InputParseException { + double xScale; + double yScale; + double zScale; + Extent extent; + if (arguments.length == 1) { + xScale = yScale = zScale = Double.parseDouble(arguments[0]); + extent = context.requireExtent(); + } else if (arguments.length == 3 || arguments.length == 4) { + xScale = Double.parseDouble(arguments[0]); + yScale = Double.parseDouble(arguments[1]); + zScale = Double.parseDouble(arguments[2]); + extent = arguments.length == 4 ? worldEdit.getTransformFactory().parseFromInput(arguments[3], context) : + context.requireExtent(); + } else { + return null; + } + return new ScaleTransform(extent, xScale, yScale, zScale); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/SpreadTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/SpreadTransformParser.java new file mode 100644 index 000000000..baaab896e --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/SpreadTransformParser.java @@ -0,0 +1,49 @@ +package com.fastasyncworldedit.core.extension.factory.parser.transform; + +import com.fastasyncworldedit.core.extension.factory.parser.RichParser; +import com.fastasyncworldedit.core.extent.ResettableExtent; +import com.fastasyncworldedit.core.extent.transform.RandomOffsetTransform; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import org.jetbrains.annotations.NotNull; + +import java.util.stream.Stream; + +public class SpreadTransformParser extends RichParser { + + /** + * Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}. + * + * @param worldEdit the worldedit instance. + */ + public SpreadTransformParser(WorldEdit worldEdit) { + super(worldEdit, "#spread", "#randomoffset"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + if (index < 3) { + return SuggestionHelper.suggestPositiveIntegers(argumentInput); + } else if (index == 3) { + return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + } + return Stream.empty(); + } + + @Override + protected ResettableExtent parseFromInput(@NotNull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length != 3 && arguments.length != 4) { + return null; + } + int xOffset = Integer.parseInt(arguments[0]); + int yOffset = Integer.parseInt(arguments[1]); + int zOffset = Integer.parseInt(arguments[2]); + Extent extent = arguments.length == 4 ? worldEdit.getTransformFactory().parseFromInput(arguments[3], context) : + context.requireExtent(); + return new RandomOffsetTransform(extent, xOffset, yOffset, zOffset); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/PrimitiveBindings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/PrimitiveBindings.java index 8a39813dd..904b3608f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/PrimitiveBindings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/PrimitiveBindings.java @@ -39,32 +39,6 @@ public class PrimitiveBindings extends Bindings { } } -// TODO: Ping @MattBDev to reimplement 2020-02-04 -// -// /** -// * Gets an {@link Extent} from a {@link Binding}. -// * -// * @param argument the context -// * @return an extent -// * @throws InputParseException on other error -// */ -// @Binding -// public ResettableExtent getResettableExtent(Actor actor, String argument) throws InputParseException { -// if (argument.equalsIgnoreCase("#null")) { -// return new NullExtent(); -// } -// DefaultTransformParser parser = Fawe.get().getTransformParser(); -// ParserContext parserContext = new ParserContext(); -// if (actor instanceof Entity) { -// Extent extent = ((Entity) actor).getExtent(); -// if (extent instanceof World) { -// parserContext.setWorld((World) extent); -// } -// } -// parserContext.setSession(WorldEdit.getInstance().getSessionManager().get(actor)); -// return parser.parseFromInput(argument, parserContext); -// } - /** * Gets a type from a {@link Binding}. * diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java index 17c59e7d0..d9e3185b0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java @@ -37,6 +37,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc this.limit = limit; } + @Override public abstract boolean contains(int x, int y, int z); public abstract boolean contains(int x, int z); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java index 82a84b3e6..f7cdb7844 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java @@ -81,74 +81,74 @@ public class NullExtent extends FaweRegionExtent implements IBatchProcessor { @Override public List getEntities() { - return Collections.emptyList(); + throw reason; } @Nullable @Override public Entity createEntity(Location arg0, BaseEntity arg1) { - return null; + throw reason; } @Override public BlockState getBlock(BlockVector3 position) { - return BlockTypes.AIR.getDefaultState(); + throw reason; } @Override public BlockState getBlock(int x, int y, int z) { - return BlockTypes.AIR.getDefaultState(); + throw reason; } @Override public BaseBlock getFullBlock(BlockVector3 position) { - return getBlock(position).toBaseBlock(); + throw reason; } @Override public BaseBlock getFullBlock(int x, int y, int z) { - return getBlock(x, y, z).toBaseBlock(); + throw reason; } @Override public BiomeType getBiome(BlockVector3 position) { - return BiomeTypes.THE_VOID; + throw reason; } @Override public BiomeType getBiomeType(int x, int y, int z) { - return BiomeTypes.THE_VOID; + throw reason; } @Override public > boolean setBlock(BlockVector3 position, B block) throws WorldEditException { - return false; + throw reason; } @Override public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { - return false; + throw reason; } @Override public ResettableExtent setExtent(Extent extent) { - return this; + throw reason; } @Override public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { - return false; + throw reason; } @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - return false; + throw reason; } @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { - return false; + throw reason; } @Override @@ -371,7 +371,7 @@ public class NullExtent extends FaweRegionExtent implements IBatchProcessor { @Override public ProcessorScope getScope() { - return ProcessorScope.ADDING_BLOCKS; + throw reason; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/OffsetExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/OffsetExtent.java deleted file mode 100644 index bd2aa14b0..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/OffsetExtent.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.fastasyncworldedit.core.extent; - -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockStateHolder; - -public class OffsetExtent extends ResettableExtent { - - private final int dx; - private final int dy; - private final int dz; - - public OffsetExtent(Extent parent, int dx, int dy, int dz) { - super(parent); - this.dx = dx; - this.dy = dy; - this.dz = dz; - } - - @Override - public boolean setBiome(BlockVector3 position, BiomeType biome) { - return getExtent() - .setBiome(position.getBlockX() + dx, position.getBlockY() + dy, position.getBlockZ() + dz, - biome - ); - } - - @Override - public boolean setBiome(int x, int y, int z, BiomeType biome) { - return getExtent().setBiome(x + dx, y + dy, z + dz, biome); - } - - @Override - public > boolean setBlock(BlockVector3 location, T block) - throws WorldEditException { - return getExtent().setBlock(location.getBlockX() + dx, location.getBlockY() + dy, - location.getBlockZ() + dz, block - ); - } - - @Override - public > boolean setBlock(int x, int y, int z, T block) - throws WorldEditException { - return getExtent().setBlock(x + dx, y + dy, z + dz, block); - } - -} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ResettableExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ResettableExtent.java index a0a4e3298..b9122d2f6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ResettableExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ResettableExtent.java @@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.extent; import com.fastasyncworldedit.core.util.ExtentTraverser; import com.fastasyncworldedit.core.util.ReflectionUtils; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; @@ -38,7 +39,7 @@ public class ResettableExtent extends AbstractDelegateExtent implements Serializ && next instanceof ResettableExtent) { ((ResettableExtent) next).setExtent(extent); } else { - new ExtentTraverser(this).setNext(new AbstractDelegateExtent(extent)); + new ExtentTraverser(this).setNext(extent); } return this; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java index f0b6d91ed..a2e5b1798 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java @@ -8,6 +8,8 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; import javax.imageio.ImageIO; import javax.imageio.stream.ImageOutputStream; @@ -136,7 +138,14 @@ public class PNGWriter implements ClipboardWriter { poly3X[3] = (int) cpx; poly3Y[3] = (int) (cpy + dpxi[1]); - Color colorTop = new Color(tu.getColor(block.getBlockType())); + BlockType type = block.getBlockType(); + int color; + if (type == BlockTypes.GRASS_BLOCK) { + color = tu.getColor(clipboard.getBiome(mutable)); + } else { + color = tu.getColor(type); + } + Color colorTop = new Color(color); g2.setColor(colorTop); if (fill) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/Linear3DTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/Linear3DTransform.java index 89d3d007e..c458bc1b2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/Linear3DTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/Linear3DTransform.java @@ -8,12 +8,18 @@ public class Linear3DTransform extends SelectTransform { private final ResettableExtent[] extentsArray; + /** + * New instance + * + * @param extents list of extents to choose from + */ public Linear3DTransform(ResettableExtent[] extents) { this.extentsArray = extents; } @Override public ResettableExtent setExtent(Extent extent) { + super.setExtent(extent); for (ResettableExtent cur : extentsArray) { cur.setExtent(extent); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/LinearTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/LinearTransform.java index 7a254e6ce..b00715f16 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/LinearTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/LinearTransform.java @@ -9,12 +9,18 @@ public class LinearTransform extends SelectTransform { private final ResettableExtent[] extentsArray; private int index; + /** + * New instance + * + * @param extents list of extents to choose from + */ public LinearTransform(ResettableExtent[] extents) { this.extentsArray = extents; } @Override public ResettableExtent setExtent(Extent extent) { + super.setExtent(extent); for (ResettableExtent cur : extentsArray) { cur.setExtent(extent); } @@ -26,7 +32,7 @@ public class LinearTransform extends SelectTransform { if (index == extentsArray.length) { index = 0; } - return extentsArray[index]; + return extentsArray[index++]; } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/MultiTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/MultiTransform.java index 0cf64e3f4..edae11174 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/MultiTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/MultiTransform.java @@ -17,6 +17,11 @@ public class MultiTransform extends RandomTransform { private ResettableExtent[] extents; + /** + * New instance + * + * @param extents list of extents to set blocks to + */ public MultiTransform(Collection extents) { for (ResettableExtent extent : extents) { add(extent, 1); @@ -65,6 +70,16 @@ public class MultiTransform extends RandomTransform { return result; } + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + // don't use streams for each block place, it'd be incredibly slow + boolean result = false; + for (AbstractDelegateExtent extent : extents) { + result |= extent.setBiome(x, y, z, biome); + } + return result; + } + @Nullable @Override public Entity createEntity(Location location, BaseEntity entity) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/OffsetTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/OffsetTransform.java new file mode 100644 index 000000000..685eef5f5 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/OffsetTransform.java @@ -0,0 +1,77 @@ +package com.fastasyncworldedit.core.extent.transform; + +import com.fastasyncworldedit.core.extent.ResettableExtent; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +public class OffsetTransform extends ResettableExtent { + + private final int dx; + private final int dy; + private final int dz; + + /** + * New instance + * + * @param parent extent to set to + * @param dx offset x + * @param dy offset y + * @param dz offset z + */ + public OffsetTransform(Extent parent, int dx, int dy, int dz) { + super(parent); + this.dx = dx; + this.dy = dy; + this.dz = dz; + } + + @Override + public boolean setBiome(BlockVector3 location, BiomeType biome) { + int x = location.getX() + dx; + int y = location.getX() + dy; + int z = location.getX() + dz; + if (!getExtent().contains(x, y, z)) { + return false; + } + return getExtent().setBiome(x, y, z, biome); + } + + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + x += dx; + y += dy; + z += dz; + if (!getExtent().contains(x, y, z)) { + return false; + } + return getExtent().setBiome(x, y, z, biome); + } + + @Override + public > boolean setBlock(BlockVector3 location, T block) + throws WorldEditException { + int x = location.getX() + dx; + int y = location.getX() + dy; + int z = location.getX() + dz; + if (!getExtent().contains(x, y, z)) { + return false; + } + return getExtent().setBlock(x, y, z, block); + } + + @Override + public > boolean setBlock(int x, int y, int z, T block) + throws WorldEditException { + x += dx; + y += dy; + z += dz; + if (!getExtent().contains(x, y, z)) { + return false; + } + return getExtent().setBlock(x, y, z, block); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/PatternTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/PatternTransform.java index 794649719..325f38f3f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/PatternTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/PatternTransform.java @@ -1,7 +1,6 @@ package com.fastasyncworldedit.core.extent.transform; import com.fastasyncworldedit.core.extent.ResettableExtent; -import com.fastasyncworldedit.core.math.MutableBlockVector3; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.Pattern; @@ -12,6 +11,12 @@ public class PatternTransform extends ResettableExtent { private final Pattern pattern; + /** + * New instance + * + * @param parent extent to set to + * @param pattern pattern to apply + */ public PatternTransform(Extent parent, Pattern pattern) { super(parent); this.pattern = pattern; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/RandomOffsetTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomOffsetTransform.java similarity index 56% rename from worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/RandomOffsetTransform.java rename to worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomOffsetTransform.java index 218ff00c3..4e80c72d7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/RandomOffsetTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomOffsetTransform.java @@ -1,5 +1,6 @@ -package com.fastasyncworldedit.core.extent; +package com.fastasyncworldedit.core.extent.transform; +import com.fastasyncworldedit.core.extent.ResettableExtent; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; @@ -15,6 +16,14 @@ public class RandomOffsetTransform extends ResettableExtent { private final int dz; private transient SplittableRandom random; + /** + * New instance + * + * @param parent extent to set to + * @param dx range of x values to choose from (0 -> x) + * @param dy range of y values to choose from (0 -> y) + * @param dz range of z values to choose from (0 -> z) + */ public RandomOffsetTransform(Extent parent, int dx, int dy, int dz) { super(parent); this.dx = dx + 1; @@ -24,10 +33,24 @@ public class RandomOffsetTransform extends ResettableExtent { } @Override - public boolean setBiome(BlockVector3 pos, BiomeType biome) { - int x = pos.getBlockX() + random.nextInt(1 + (dx << 1)) - dx; - int y = pos.getBlockY() + random.nextInt(1 + (dy << 1)) - dy; - int z = pos.getBlockZ() + random.nextInt(1 + (dz << 1)) - dz; + public boolean setBiome(BlockVector3 position, BiomeType biome) { + int x = position.getBlockX() + random.nextInt(1 + (dx << 1)) - dx; + int y = position.getBlockY() + random.nextInt(1 + (dy << 1)) - dy; + int z = position.getBlockZ() + random.nextInt(1 + (dz << 1)) - dz; + if (!getExtent().contains(x, y, z)) { + return false; + } + return getExtent().setBiome(x, y, z, biome); + } + + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + x = x + random.nextInt(1 + (dx << 1)) - dx; + y = y + random.nextInt(1 + (dy << 1)) - dy; + z = z + random.nextInt(1 + (dz << 1)) - dz; + if (!getExtent().contains(x, y, z)) { + return false; + } return getExtent().setBiome(x, y, z, biome); } @@ -37,6 +60,9 @@ public class RandomOffsetTransform extends ResettableExtent { int x = pos.getBlockX() + random.nextInt(1 + (dx << 1)) - dx; int y = pos.getBlockY() + random.nextInt(1 + (dy << 1)) - dy; int z = pos.getBlockZ() + random.nextInt(1 + (dz << 1)) - dz; + if (!getExtent().contains(x, y, z)) { + return false; + } return getExtent().setBlock(x, y, z, block); } @@ -46,6 +72,9 @@ public class RandomOffsetTransform extends ResettableExtent { x = x + random.nextInt(1 + (dx << 1)) - dx; y = y + random.nextInt(1 + (dy << 1)) - dy; z = z + random.nextInt(1 + (dz << 1)) - dz; + if (!getExtent().contains(x, y, z)) { + return false; + } return getExtent().setBlock(x, y, z, block); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomTransform.java index 9518d7dee..93ab1ac99 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomTransform.java @@ -29,6 +29,11 @@ public class RandomTransform extends SelectTransform { this(new TrueRandom()); } + /** + * New instance + * + * @param random {@link SimpleRandom} used to choose between transforms, given weights + */ public RandomTransform(SimpleRandom random) { this.random = random; } @@ -49,6 +54,7 @@ public class RandomTransform extends SelectTransform { collection = RandomCollection.of(weights, random); extents = new LinkedHashSet<>(weights.keySet()); } + super.setExtent(extent); for (ResettableExtent current : extents) { current.setExtent(extent); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java index 33053813b..fc7424868 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java @@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.extent.transform; import com.fastasyncworldedit.core.extent.ResettableExtent; import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.math.MutableVector3; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; @@ -18,61 +19,76 @@ public class ScaleTransform extends ResettableExtent { private final double dx; private final double dy; private final double dz; - private transient MutableBlockVector3 mutable = new MutableBlockVector3(); + private transient MutableVector3 mutable = new MutableVector3(); + private transient int minY; private transient int maxy; private transient BlockVector3 min; - + /** + * New instance + * + * @param parent extent to set to + * @param dx x axis scaling + * @param dy y axis scaling + * @param dz z axis scaling + */ public ScaleTransform(Extent parent, double dx, double dy, double dz) { super(parent); this.dx = dx; this.dy = dy; this.dz = dz; - this.maxy = parent.getMaximumPoint().getBlockY(); + this.minY = parent.getMinY(); + this.maxy = parent.getMaxY(); } @Override public ResettableExtent setExtent(Extent extent) { min = null; - maxy = extent.getMaximumPoint().getBlockY(); - mutable = new MutableBlockVector3(); + mutable = new MutableVector3(); + this.minY = extent.getMinY(); + this.maxy = extent.getMaxY(); return super.setExtent(extent); } - private void getPos(BlockVector3 pos) { + private MutableVector3 getPos(BlockVector3 pos) { if (min == null) { min = pos; } mutable.mutX(min.getX() + (pos.getX() - min.getX()) * dx); mutable.mutY(min.getY() + (pos.getY() - min.getY()) * dy); mutable.mutZ(min.getZ() + (pos.getZ() - min.getZ()) * dz); + return new MutableVector3(mutable); } - private void getPos(int x, int y, int z) { + private MutableVector3 getPos(int x, int y, int z) { if (min == null) { min = BlockVector3.at(x, y, z); } mutable.mutX(min.getX() + (x - min.getX()) * dx); mutable.mutY(min.getY() + (y - min.getY()) * dy); mutable.mutZ(min.getZ() + (z - min.getZ()) * dz); + return new MutableVector3(mutable); } - @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { boolean result = false; - getPos(location); - double sx = mutable.getX(); - double sy = mutable.getY(); - double sz = mutable.getZ(); + MutableVector3 vector3 = getPos(location); + MutableBlockVector3 pos = new MutableBlockVector3(); + double sx = vector3.getX(); + double sy = vector3.getY(); + double sz = vector3.getZ(); double ex = sx + dx; - double ey = Math.min(maxy, sy + dy); + double ey = Math.max(minY, Math.min(maxy, sy + dy)); double ez = sz + dz; - for (mutable.mutY(sy); mutable.getY() < ey; mutable.mutY(mutable.getY() + 1)) { - for (mutable.mutZ(sz); mutable.getZ() < ez; mutable.mutZ(mutable.getZ() + 1)) { - for (mutable.mutX(sx); mutable.getX() < ex; mutable.mutX(mutable.getX() + 1)) { - result |= super.setBlock(mutable, block); + for (pos.mutY(sy); pos.getY() < ey; pos.mutY(pos.getY() + 1)) { + for (pos.mutZ(sz); pos.getZ() < ez; pos.mutZ(pos.getZ() + 1)) { + for (pos.mutX(sx); pos.getX() < ex; pos.mutX(pos.getX() + 1)) { + if (!getExtent().contains(pos)) { + continue; + } + result |= super.setBlock(pos, block); } } } @@ -82,17 +98,21 @@ public class ScaleTransform extends ResettableExtent { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { boolean result = false; - getPos(position); - double sx = mutable.getX(); - double sy = mutable.getY(); - double sz = mutable.getZ(); + MutableVector3 vector3 = getPos(position); + MutableBlockVector3 pos = new MutableBlockVector3(); + double sx = vector3.getX(); + double sy = vector3.getY(); + double sz = vector3.getZ(); double ex = sx + dx; - double ey = Math.min(maxy, sy + dy); + double ey = Math.max(minY, Math.min(maxy, sy + dy)); double ez = sz + dz; - for (mutable.mutY(sy); mutable.getY() < ey; mutable.mutY(mutable.getY() + 1)) { - for (mutable.mutZ(sz); mutable.getZ() < ez; mutable.mutZ(mutable.getZ() + 1)) { - for (mutable.mutX(sx); mutable.getX() < ex; mutable.mutX(mutable.getX() + 1)) { - result |= super.setBiome(mutable, biome); + for (pos.mutY(sy); pos.getY() < ey; pos.mutY(pos.getY() + 1)) { + for (pos.mutZ(sz); pos.getZ() < ez; pos.mutZ(pos.getZ() + 1)) { + for (pos.mutX(sx); pos.getX() < ex; pos.mutX(pos.getX() + 1)) { + if (!getExtent().contains(pos)) { + continue; + } + result |= super.setBiome(pos, biome); } } } @@ -103,17 +123,45 @@ public class ScaleTransform extends ResettableExtent { public > boolean setBlock(int x1, int y1, int z1, B block) throws WorldEditException { boolean result = false; - getPos(x1, y1, z1); - double sx = mutable.getX(); - double sy = mutable.getY(); - double sz = mutable.getZ(); - double ex = mutable.getX() + dx; + MutableVector3 vector3 = getPos(x1, y1, z1); + MutableBlockVector3 pos = new MutableBlockVector3(); + double sx = vector3.getX(); + double sy = vector3.getY(); + double sz = vector3.getZ(); + double ex = vector3.getX() + dx; double ey = Math.min(maxy, sy + dy); - double ez = mutable.getZ() + dz; - for (mutable.mutY(sy); mutable.getY() < ey; mutable.mutY(mutable.getY() + 1)) { - for (mutable.mutZ(sz); mutable.getZ() < ez; mutable.mutZ(mutable.getZ() + 1)) { - for (mutable.mutX(sx); mutable.getX() < ex; mutable.mutX(mutable.getX() + 1)) { - result |= super.setBlock(mutable, block); + double ez = vector3.getZ() + dz; + for (pos.mutY(sy); pos.getY() < ey; pos.mutY(pos.getY() + 1)) { + for (pos.mutZ(sz); pos.getZ() < ez; pos.mutZ(pos.getZ() + 1)) { + for (pos.mutX(sx); pos.getX() < ex; pos.mutX(pos.getX() + 1)) { + if (!getExtent().contains(pos)) { + continue; + } + result |= super.setBlock(pos, block); + } + } + } + return result; + } + + @Override + public boolean setBiome(int x1, int y1, int z1, BiomeType biome) { + boolean result = false; + MutableVector3 vector3 = getPos(x1, y1, z1); + MutableBlockVector3 pos = new MutableBlockVector3(); + double sx = vector3.getX(); + double sy = vector3.getY(); + double sz = vector3.getZ(); + double ex = sx + dx; + double ey = Math.max(minY, Math.min(maxy, sy + dy)); + double ez = sz + dz; + for (pos.mutY(sy); pos.getY() < ey; pos.mutY(pos.getY() + 1)) { + for (pos.mutZ(sz); pos.getZ() < ez; pos.mutZ(pos.getZ() + 1)) { + for (pos.mutX(sx); pos.getX() < ex; pos.mutX(pos.getX() + 1)) { + if (!getExtent().contains(pos)) { + continue; + } + result |= super.setBiome(pos, biome); } } } @@ -123,11 +171,13 @@ public class ScaleTransform extends ResettableExtent { @Nullable @Override public Entity createEntity(Location location, BaseEntity entity) { - getPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); Location newLoc = new Location(location.getExtent(), - mutable.toVector3(), + getPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), location.getYaw(), location.getPitch() ); + if (!getExtent().contains(newLoc.toBlockPoint())) { + return null; + } return super.createEntity(newLoc, entity); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java index 1c1a95d03..c5cda5ff7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java @@ -57,4 +57,9 @@ public abstract class SelectTransform extends ResettableExtent { return getExtent(position).setBiome(position, biome); } + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + return getExtent(x, y, z).setBiome(x, y, z, biome); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java index 0a3df374f..45aebfa07 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java @@ -7,6 +7,7 @@ import com.fastasyncworldedit.core.registry.state.PropertyKey; import com.fastasyncworldedit.core.registry.state.PropertyKeySet; import com.fastasyncworldedit.core.util.MutableCharSequence; import com.fastasyncworldedit.core.util.StringMan; +import com.fastasyncworldedit.core.world.block.BlanketBaseBlock; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.BlockMask; @@ -423,6 +424,9 @@ public class BlockMaskBuilder { public > BlockMaskBuilder add(BlockStateHolder state) { BlockType type = state.getBlockType(); + if (state instanceof BlanketBaseBlock) { + return add(type); + } int i = type.getInternalId(); long[] states = bitSets[i]; if (states != ALL) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AngleColorPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AngleColorPattern.java index 77c98537d..892e1830a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AngleColorPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AngleColorPattern.java @@ -3,22 +3,31 @@ package com.fastasyncworldedit.core.function.pattern; import com.fastasyncworldedit.core.util.TextureHolder; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; -public class AngleColorPattern extends DataAnglePattern { +public class AngleColorPattern extends AnglePattern { protected transient TextureHolder holder; + /** + * Create a new {@link Pattern} instance + * + * @param extent extent to set to + * @param holder {@link TextureHolder} to use to get textures + * @param distance distance to use to calculate angle + */ public AngleColorPattern(Extent extent, TextureHolder holder, int distance) { super(extent, distance); this.holder = holder.getTextureUtil(); } - public int getColor(int color, int slope) { + private int getColor(int color, int slope) { if (slope == 0) { return color; } @@ -54,7 +63,13 @@ public class AngleColorPattern extends DataAnglePattern { if (slope == -1) { return block; } - int color = holder.getTextureUtil().getColor(block.getBlockType()); + BlockType type = block.getBlockType(); + int color; + if (type == BlockTypes.GRASS_BLOCK) { + color = holder.getTextureUtil().getColor(extent.getBiome(position)); + } else { + color = holder.getTextureUtil().getColor(type); + } if (color == 0) { return block; } @@ -69,7 +84,13 @@ public class AngleColorPattern extends DataAnglePattern { if (slope == -1) { return false; } - int color = holder.getTextureUtil().getColor(block.getBlockType()); + BlockType type = block.getBlockType(); + int color; + if (type == BlockTypes.GRASS_BLOCK) { + color = holder.getTextureUtil().getColor(extent.getBiome(get)); + } else { + color = holder.getTextureUtil().getColor(type); + } if (color == 0) { return false; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/DataAnglePattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AnglePattern.java similarity index 68% rename from worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/DataAnglePattern.java rename to worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AnglePattern.java index aef2fd2d8..6c8ca56dc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/DataAnglePattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AnglePattern.java @@ -1,22 +1,27 @@ package com.fastasyncworldedit.core.function.pattern; import com.fastasyncworldedit.core.extent.ExtentHeightCacher; -import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; -public class DataAnglePattern extends AbstractPattern { +public abstract class AnglePattern extends AbstractPattern { public final double factor; public final Extent extent; public final int maxY; public final int distance; - public DataAnglePattern(Extent extent, int distance) { + /** + * Create a new {@link Pattern} instance + * + * @param extent extent to set to + * @param distance distance to calculate angle with + */ + public AnglePattern(Extent extent, int distance) { this.extent = new ExtentHeightCacher(extent); this.maxY = extent.getMaximumPoint().getBlockY(); this.distance = distance; @@ -58,25 +63,9 @@ public class DataAnglePattern extends AbstractPattern { } @Override - public BaseBlock applyBlock(BlockVector3 position) { - BlockState block = extent.getBlock(position); - int slope = getSlope(block, position, extent); - if (slope == -1) { - return block.toBaseBlock(); - } - int data = Math.min(slope, 255) >> 4; - return block.withPropertyId(data).toBaseBlock(); - } + public abstract BaseBlock applyBlock(BlockVector3 position); @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - BlockState block = extent.getBlock(getPosition); - int slope = getSlope(block, getPosition, extent); - if (slope == -1) { - return false; - } - int data = Math.min(slope, 255) >> 4; - return extent.setBlock(setPosition, block.withPropertyId(data)); - } + public abstract boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AverageColorPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AverageColorPattern.java index 4928c34c8..af08889fa 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AverageColorPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AverageColorPattern.java @@ -1,12 +1,15 @@ package com.fastasyncworldedit.core.function.pattern; +import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TextureHolder; import com.fastasyncworldedit.core.util.TextureUtil; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; import java.awt.Color; @@ -15,18 +18,35 @@ public class AverageColorPattern extends AbstractExtentPattern { private final transient TextureHolder holder; private final int color; - public AverageColorPattern(Extent extent, int color, TextureHolder util) { + /** + * Create a new {@link Pattern} instance + * + * @param extent extent to set to + * @param holder {@link TextureHolder} to use to get textures + * @param r red channel, clamped 0 -> 255 + * @param g green channel, clamped 0 -> 255 + * @param b blue channel, clamped 0 -> 255 + * @param a alpha channel, clamped 0 -> 255 + */ + public AverageColorPattern(Extent extent, TextureHolder holder, int r, int g, int b, int a) { super(extent); - this.holder = util; - this.color = new Color(color).getRGB(); + this.holder = holder; + this.color = new Color(MathMan.clamp(r, 0, 255), MathMan.clamp(g, 0, 255), MathMan.clamp(b, 0, 255), MathMan.clamp(a, 0 + , 255)).getRGB(); } @Override public BaseBlock applyBlock(BlockVector3 position) { BaseBlock block = getExtent().getFullBlock(position); TextureUtil util = holder.getTextureUtil(); - int currentColor = util.getColor(block.getBlockType()); - int newColor = util.averageColor(currentColor, color); + BlockType type = block.getBlockType(); + int currentColor; + if (type == BlockTypes.GRASS_BLOCK) { + currentColor = holder.getTextureUtil().getColor(getExtent().getBiome(position)); + } else { + currentColor = holder.getTextureUtil().getColor(type); + } + int newColor = TextureUtil.averageColor(currentColor, color); return util.getNearestBlock(newColor).getDefaultState().toBaseBlock(); } @@ -34,11 +54,16 @@ public class AverageColorPattern extends AbstractExtentPattern { public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { BlockType blockType = get.getBlock(extent).getBlockType(); TextureUtil util = holder.getTextureUtil(); - int currentColor = util.getColor(blockType); + int currentColor; + if (blockType == BlockTypes.GRASS_BLOCK) { + currentColor = holder.getTextureUtil().getColor(extent.getBiome(get)); + } else { + currentColor = holder.getTextureUtil().getColor(blockType); + } if (currentColor == 0) { return false; } - int newColor = util.averageColor(currentColor, color); + int newColor = TextureUtil.averageColor(currentColor, color); BlockType newBlock = util.getNearestBlock(newColor); if (newBlock == blockType) { return false; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BiomeApplyingPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BiomeApplyingPattern.java index 9f9758bd8..35f4733ba 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BiomeApplyingPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BiomeApplyingPattern.java @@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.function.pattern; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; @@ -10,6 +11,12 @@ public class BiomeApplyingPattern extends AbstractExtentPattern { private final BiomeType biomeType; + /** + * Create a new {@link Pattern} instance + * + * @param extent extent to set to + * @param biomeType biome type to set + */ public BiomeApplyingPattern(Extent extent, BiomeType biomeType) { super(extent); this.biomeType = biomeType; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java index 3c0a96130..84cc42d45 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java @@ -11,8 +11,6 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; -import java.util.UUID; - public class BufferedPattern extends AbstractPattern implements ResettablePattern { protected final LocalBlockVectorSet set = new LocalBlockVectorSet(); @@ -20,10 +18,14 @@ public class BufferedPattern extends AbstractPattern implements ResettablePatter protected final long[] actionTime; protected final Pattern pattern; - protected final UUID uuid; + /** + * Create a new {@link Pattern} instance + * + * @param actor actor associated with the pattern + * @param parent pattern to set + */ public BufferedPattern(Actor actor, Pattern parent) { - this.uuid = actor.getUniqueId(); long[] tmp = actor.getMeta("lastActionTime"); if (tmp == null) { actor.setMeta("lastActionTime", tmp = new long[2]); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java index 78f7bd08d..379c263c7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java @@ -6,6 +6,12 @@ import com.sk89q.worldedit.math.BlockVector3; public class BufferedPattern2D extends BufferedPattern { + /** + * Create a new {@link Pattern} instance + * + * @param actor actor associated with the pattern + * @param parent pattern to set + */ public BufferedPattern2D(Actor actor, Pattern parent) { super(actor, parent); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/DataPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/DataPattern.java deleted file mode 100644 index 8173587b8..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/DataPattern.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.fastasyncworldedit.core.function.pattern; - -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class DataPattern extends AbstractExtentPattern { - - private final Pattern pattern; - - public DataPattern(Extent extent, Pattern parent) { - super(extent); - checkNotNull(parent); - this.pattern = parent; - } - - @Override - public BaseBlock applyBlock(BlockVector3 position) { - BaseBlock oldBlock = getExtent().getFullBlock(position); - BaseBlock newBlock = pattern.applyBlock(position); - return oldBlock.toBlockState().withProperties(newBlock.toBlockState()).toBaseBlock(newBlock.getNbtData()); - } - - @Override - public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - BaseBlock oldBlock = get.getFullBlock(extent); - BaseBlock newBlock = pattern.applyBlock(get); - - BlockState oldState = oldBlock.toBlockState(); - BlockState newState = oldState.withProperties(newBlock.toBlockState()); - if (newState != oldState) { - if (oldBlock.hasNbtData()) { - set.setFullBlock(extent, newState.toBaseBlock(oldBlock.getNbtData())); - } else { - set.setBlock(extent, newState); - } - return true; - } - return false; - } - -} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/DesaturatePattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/DesaturatePattern.java index 27d1c1e83..49eff4531 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/DesaturatePattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/DesaturatePattern.java @@ -5,9 +5,11 @@ import com.fastasyncworldedit.core.util.TextureUtil; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; public class DesaturatePattern extends AbstractPattern { @@ -15,21 +17,33 @@ public class DesaturatePattern extends AbstractPattern { private final Extent extent; private final double value; - public DesaturatePattern(Extent extent, double value, TextureHolder util) { + /** + * Create a new {@link Pattern} instance + * + * @param extent extent to set to + * @param holder {@link TextureHolder} to use for textures + * @param value decimal percent to desaturate by (0 -> 1) + */ + public DesaturatePattern(Extent extent, TextureHolder holder, double value) { this.extent = extent; - this.holder = util; + this.holder = holder; this.value = Math.max(0, Math.min(1, value)); } @Override public BaseBlock applyBlock(BlockVector3 position) { - BlockType block = extent.getBlock(position).getBlockType(); + BlockType type = extent.getBlock(position).getBlockType(); TextureUtil util = holder.getTextureUtil(); - int color = getColor(util.getColor(block)); + int color; + if (type == BlockTypes.GRASS_BLOCK) { + color = holder.getTextureUtil().getColor(extent.getBiome(position)); + } else { + color = holder.getTextureUtil().getColor(type); + } return util.getNearestBlock(color).getDefaultState().toBaseBlock(); } - public int getColor(int color) { + private int getColor(int color) { int r = (color >> 16) & 0xFF; int g = (color >> 8) & 0xFF; int b = (color >> 0) & 0xFF; @@ -45,7 +59,12 @@ public class DesaturatePattern extends AbstractPattern { public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { BlockType type = get.getBlock(extent).getBlockType(); TextureUtil util = holder.getTextureUtil(); - int color = util.getColor(type); + int color; + if (type == BlockTypes.GRASS_BLOCK) { + color = holder.getTextureUtil().getColor(extent.getBiome(get)); + } else { + color = holder.getTextureUtil().getColor(type); + } int newColor = getColor(color); if (newColor == color) { return false; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExistingPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExistingPattern.java index 30299837d..9dfb18567 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExistingPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExistingPattern.java @@ -2,11 +2,17 @@ package com.fastasyncworldedit.core.function.pattern; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; public class ExistingPattern extends AbstractExtentPattern { + /** + * Create a new {@link Pattern} instance + * + * @param extent extent to set to + */ public ExistingPattern(Extent extent) { super(extent); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/IdDataMaskPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/IdDataMaskPattern.java deleted file mode 100644 index a95f1863a..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/IdDataMaskPattern.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.fastasyncworldedit.core.function.pattern; - -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BaseBlock; - -public class IdDataMaskPattern extends AbstractExtentPattern { - - private final Pattern pattern; - private final int bitMask; - - public IdDataMaskPattern(Extent extent, Pattern parent, int bitMask) { - super(extent); - this.pattern = parent; - this.bitMask = bitMask; - } - - @Override - public BaseBlock applyBlock(BlockVector3 position) { - BaseBlock oldBlock = getExtent().getFullBlock(position); - BaseBlock newBlock = pattern.applyBlock(position); - int oldData = oldBlock.getInternalPropertiesId(); - int newData = newBlock.getInternalPropertiesId() + oldData - (oldData & bitMask); - return newBlock.withPropertyId(newData).toBaseBlock(); - } - -} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/IdPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/IdPattern.java deleted file mode 100644 index f0b312baf..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/IdPattern.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.fastasyncworldedit.core.function.pattern; - -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BaseBlock; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class IdPattern extends AbstractExtentPattern { - - private final Pattern pattern; - - public IdPattern(Extent extent, Pattern parent) { - super(extent); - checkNotNull(parent); - this.pattern = parent; - } - - @Override - public BaseBlock applyBlock(BlockVector3 position) { - BaseBlock oldBlock = getExtent().getFullBlock(position); - BaseBlock newBlock = pattern.applyBlock(position); - return newBlock.withPropertyId(oldBlock.getInternalPropertiesId()).toBaseBlock(); - } - -} 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 e621e6c9e..0762eb67c 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 @@ -13,6 +13,13 @@ public class Linear2DBlockPattern extends AbstractPattern { private final int xScale; private final int zScale; + /** + * Create a new {@link Pattern} instance + * + * @param patterns array of patterns to linearly choose from based on x/z coordinates + * @param xScale x-axis scale + * @param zScale z-axis scale + */ public Linear2DBlockPattern(Pattern[] patterns, int xScale, int zScale) { this.patternsArray = patterns; this.xScale = xScale; 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 7756bf6de..c132fbcdd 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 @@ -14,6 +14,14 @@ public class Linear3DBlockPattern extends AbstractPattern { private final int yScale; private final int zScale; + /** + * Create a new {@link Pattern} instance + * + * @param patterns array of patterns to linearly choose from based on x/y/z coordinates + * @param xScale x-axis scale + * @param yScale y-axis scale + * @param zScale z-axis scale + */ public Linear3DBlockPattern(Pattern[] patterns, int xScale, int yScale, int zScale) { this.patternsArray = patterns; this.xScale = xScale; 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 d89a9a31d..086cf3a31 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 @@ -12,6 +12,11 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat private final Pattern[] patternsArray; private transient int index; + /** + * Create a new {@link Pattern} instance + * + * @param patterns array of patterns to linearly choose from based on x/z coordinates + */ public LinearBlockPattern(Pattern[] patterns) { this.patternsArray = patterns; } 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 d5f2bedaf..5d840d771 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 @@ -14,6 +14,13 @@ public class MaskedPattern extends AbstractPattern { private final Pattern secondary; private final Mask mask; + /** + * Create a new {@link Pattern} instance + * + * @param mask mask to use + * @param primary pattern if mask true + * @param secondary pattern if mask false + */ public MaskedPattern(Mask mask, Pattern primary, Pattern secondary) { this.mask = mask; this.primary = primary; 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 a1bd54985..d9fefb1bc 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 @@ -13,6 +13,11 @@ public class NoXPattern extends AbstractPattern { private final Pattern pattern; private final MutableBlockVector3 mutable = new MutableBlockVector3(); + /** + * Create a new {@link Pattern} instance + * + * @param pattern pattern to apply + */ public NoXPattern(Pattern pattern) { this.pattern = pattern; } 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 aea7a0879..05d26f496 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 @@ -13,6 +13,11 @@ public class NoYPattern extends AbstractPattern { private final Pattern pattern; private final MutableBlockVector3 mutable = new MutableBlockVector3(); + /** + * Create a new {@link Pattern} instance + * + * @param pattern pattern to apply + */ public NoYPattern(Pattern pattern) { this.pattern = pattern; } 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 5f4189066..faebb59aa 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 @@ -11,13 +11,17 @@ import com.sk89q.worldedit.world.block.BaseBlock; public class NoZPattern extends AbstractPattern { private final Pattern pattern; + private final MutableBlockVector3 mutable = new MutableBlockVector3(); + /** + * Create a new {@link Pattern} instance + * + * @param pattern pattern to apply + */ public NoZPattern(Pattern pattern) { this.pattern = pattern; } - private final transient MutableBlockVector3 mutable = new MutableBlockVector3(); - @Override public BaseBlock applyBlock(BlockVector3 pos) { mutable.mutX(pos.getX()); 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 75ce9606a..eda121d6d 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 @@ -13,13 +13,27 @@ public class OffsetPattern extends AbstractPattern { private final int dx; private final int dy; private final int dz; + private final int minY; + private final int maxY; private final transient MutableBlockVector3 mutable = new MutableBlockVector3(); private final Pattern pattern; - public OffsetPattern(Pattern pattern, int dx, int dy, int dz) { + /** + * Create a new {@link Pattern} instance + * + * @param pattern pattern to apply + * @param dx offset x + * @param dy offset y + * @param dz offset z + * @param minY min applicable y (inclusive + * @param maxY max applicable y (inclusive + */ + public OffsetPattern(Pattern pattern, int dx, int dy, int dz, int minY, int maxY) { this.dx = dx; this.dy = dy; this.dz = dz; + this.minY = minY; + this.maxY = maxY; this.pattern = pattern; } @@ -35,6 +49,9 @@ public class OffsetPattern extends AbstractPattern { public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { mutable.mutX(get.getX() + dx); mutable.mutY(get.getY() + dy); + if (mutable.getY() < minY || mutable.getY() > maxY) { + return false; + } mutable.mutZ(get.getZ() + dz); return pattern.apply(extent, get, mutable); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/PropertyPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/PropertyPattern.java deleted file mode 100644 index c7e7e83c3..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/PropertyPattern.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.fastasyncworldedit.core.function.pattern; - -import com.fastasyncworldedit.core.registry.state.PropertyKey; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.MutableCharSequence; -import com.fastasyncworldedit.core.util.StringMan; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.registry.state.AbstractProperty; -import com.sk89q.worldedit.registry.state.IntegerProperty; -import com.sk89q.worldedit.registry.state.Property; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; - -import java.util.ArrayList; -import java.util.List; - -public class PropertyPattern extends AbstractExtentPattern { - - private final int[] transformed; - - public PropertyPattern(Extent extent, String[] properties) { - this(extent); - addRegex(".*[" + StringMan.join(properties, ",") + "]"); - } - - public PropertyPattern(Extent extent) { - super(extent); - this.transformed = new int[BlockTypesCache.states.length]; - for (int i = 0; i < transformed.length; i++) { - transformed[i] = i; - } - } - - private static final Operator EQUAL = (length, value, index) -> value; - private static final Operator PLUS = (length, value, index) -> index + value; - private static final Operator MINUS = (length, value, index) -> index - value; - private static final Operator MODULO = (length, value, index) -> index % value; - private static final Operator AND = (length, value, index) -> index & value; - private static final Operator OR = (length, value, index) -> index | value; - private static final Operator XOR = (length, value, index) -> index ^ value; - - private interface Operator { - - int apply(int length, int value, int index); - - } - - private Operator getOp(char c) { - switch (c) { - case '=': - return EQUAL; - case '+': - return PLUS; - case '-': - return MINUS; - case '%': - return MODULO; - case '&': - return AND; - case '|': - return OR; - case '^': - return XOR; - default: - return null; - } - } - - private void add(BlockType type, PropertyKey key, Operator operator, MutableCharSequence value, boolean wrap) { - if (!type.hasProperty(key)) { - return; - } - AbstractProperty property = (AbstractProperty) type.getProperty(key); - BlockState defaultState = type.getDefaultState(); - int valueInt; - if (value.length() == 0) { - valueInt = property.getIndex(defaultState.getInternalId()); - } else if (!(property instanceof IntegerProperty) && MathMan.isInteger(value)) { - valueInt = StringMan.parseInt(value); - } else { - valueInt = property.getIndexFor(value); - } - List values = property.getValues(); - int length = values.size(); - - for (int i = 0; i < values.size(); i++) { - int result = operator.apply(length, valueInt, i); - if (wrap) { - result = MathMan.wrap(result, 0, length - 1); - } else { - result = Math.max(Math.min(result, length - 1), 0); - } - if (result == i) { - continue; - } - - int internalId = valueInt + i; - - int state = property.modifyIndex(0, i); - if (type.getProperties().size() > 1) { - ArrayList properties = new ArrayList<>(type.getProperties().size() - 1); - for (Property current : type.getProperties()) { - if (current == property) { - continue; - } - properties.add(current); - } - applyRecursive(type, property, properties, 0, state, result); - } else { - int ordinal = type.withStateId(internalId).getOrdinal(); - transformed[ordinal] = type.withStateId(result).getOrdinal(); - } - } - } - - private void applyRecursive( - BlockType type, - AbstractProperty property, - List properties, - int propertiesIndex, - int stateId, - int index - ) { - AbstractProperty current = (AbstractProperty) properties.get(propertiesIndex); - List values = current.getValues(); - if (propertiesIndex + 1 < properties.size()) { - for (int i = 0; i < values.size(); i++) { - int newState = current.modifyIndex(stateId, i); - applyRecursive(type, property, properties, propertiesIndex + 1, newState, index); - } - } else { - for (int i = 0; i < values.size(); i++) { - int statesIndex = current.modifyIndex(stateId, i) >> BlockTypesCache.BIT_OFFSET; - BlockState state = type.withPropertyId(statesIndex); - - int existingOrdinal = transformed[state.getOrdinal()]; - int existing = BlockTypesCache.states[existingOrdinal].getInternalId(); - //states[statesIndex] << BlockTypesCache.BIT_OFFSET; - BlockState newState = state.withPropertyId(property.modifyIndex(existing, index) >> BlockTypesCache.BIT_OFFSET); - transformed[state.getOrdinal()] = newState.getOrdinal(); - } - } - } - - public PropertyPattern addRegex(String input) { - if (input.charAt(input.length() - 1) == ']') { - int propStart = StringMan.findMatchingBracket(input, input.length() - 1); - if (propStart == -1) { - return this; - } - - MutableCharSequence charSequence = MutableCharSequence.getTemporal(); - charSequence.setString(input); - charSequence.setSubstring(0, propStart); - - BlockType type = null; - List blockTypeList = null; - if (StringMan.isAlphanumericUnd(charSequence)) { - type = BlockTypes.get(charSequence); - } else { - String regex = charSequence.toString(); - blockTypeList = new ArrayList<>(); - for (BlockType myType : BlockTypesCache.values) { - if (myType.getId().matches(regex)) { - blockTypeList.add(myType); - } - } - if (blockTypeList.size() == 1) { - type = blockTypeList.get(0); - } - } - - PropertyKey key = null; - int length = input.length(); - int last = propStart + 1; - Operator operator = null; - boolean wrap = false; - for (int i = last; i < length; i++) { - char c = input.charAt(i); - switch (c) { - case '[': - case '{': - case '(': - int next = StringMan.findMatchingBracket(input, i); - if (next != -1) { - i = next; - } - break; - case ']': - case ',': { - charSequence.setSubstring(last, i); - char firstChar = input.charAt(last + 1); - if (type != null) { - add(type, key, operator, charSequence, wrap); - } else { - for (BlockType myType : blockTypeList) { - add(myType, key, operator, charSequence, wrap); - } - } - last = i + 1; - break; - } - default: - Operator tmp = getOp(c); - if (tmp != null) { - operator = tmp; - charSequence.setSubstring(last, i); - char cp = input.charAt(i + 1); - boolean extra = cp == '='; - wrap = cp == '~'; - if (extra || wrap) { - i++; - } - if (charSequence.length() > 0) { - key = PropertyKey.getByName(charSequence); - } - last = i + 1; - } - break; - } - } - } - return this; - } - - @Override - public BaseBlock applyBlock(BlockVector3 position) { - BaseBlock block = getExtent().getFullBlock(position); - return apply(block, block); - } - - public BaseBlock apply(BaseBlock block, BaseBlock orDefault) { - int ordinal = block.getOrdinal(); - int newOrdinal = transformed[ordinal]; - if (newOrdinal != ordinal) { - CompoundTag nbt = block.getNbtData(); - BlockState newState = BlockState.getFromOrdinal(newOrdinal); - return newState.toBaseBlock(nbt); - } - return orDefault; - } - - @Override - public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - int ordinal = get.getOrdinal(extent); - int newOrdinal = transformed[ordinal]; - if (newOrdinal != ordinal) { - set.setOrdinal(extent, newOrdinal); - } - return false; - } - -} 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 e34d16a7b..9f0791eba 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 @@ -4,6 +4,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.pattern.AbstractPattern; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.AffineTransform; @@ -18,16 +19,21 @@ import static com.google.common.base.Preconditions.checkNotNull; public class RandomFullClipboardPattern extends AbstractPattern { - private final Extent extent; private final List clipboards; private final boolean randomRotate; private final boolean randomFlip; private final Vector3 flipVector = Vector3.at(1, 0, 0).multiply(-2).add(1, 1, 1); - public RandomFullClipboardPattern(Extent extent, List clipboards, boolean randomRotate, boolean randomFlip) { + /** + * Create a new {@link Pattern} instance + * + * @param clipboards list of clipboards to choose from. Does not paste air + * @param randomRotate if the clipboard should be randomly rotated (through multiples of 90) + * @param randomFlip if the clipboard should be randomly flipped + */ + public RandomFullClipboardPattern(List clipboards, boolean randomRotate, boolean randomFlip) { checkNotNull(clipboards); this.clipboards = clipboards; - this.extent = extent; this.randomRotate = randomRotate; this.randomFlip = randomFlip; } @@ -40,7 +46,7 @@ public class RandomFullClipboardPattern extends AbstractPattern { transform = transform.rotateY(ThreadLocalRandom.current().nextInt(4) * 90); holder.setTransform(new AffineTransform().rotateY(ThreadLocalRandom.current().nextInt(4) * 90)); } - if (randomFlip) { + if (randomFlip && ThreadLocalRandom.current().nextBoolean()) { transform = transform.scale(flipVector); } if (!transform.isIdentity()) { 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 e42ea84b5..aae82e9fe 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 @@ -15,6 +15,8 @@ public class RandomOffsetPattern extends AbstractPattern { private final int dx; private final int dy; private final int dz; + private final int minY; + private final int maxY; private final Pattern pattern; private final transient int dx2; @@ -23,7 +25,17 @@ public class RandomOffsetPattern extends AbstractPattern { private final transient MutableBlockVector3 mutable = new MutableBlockVector3(); private final transient SplittableRandom r; - public RandomOffsetPattern(Pattern pattern, int dx, int dy, int dz) { + /** + * Create a new {@link Pattern} instance + * + * @param pattern pattern to apply + * @param dx offset x + * @param dy offset y + * @param dz offset z + * @param minY min applicable y (inclusive + * @param maxY max applicable y (inclusive + */ + public RandomOffsetPattern(Pattern pattern, int dx, int dy, int dz, int minY, int maxY) { this.pattern = pattern; this.dx = dx; this.dy = dy; @@ -32,6 +44,8 @@ public class RandomOffsetPattern extends AbstractPattern { this.dy2 = dy * 2 + 1; this.dz2 = dz * 2 + 1; this.r = new SplittableRandom(); + this.minY = minY; + this.maxY = maxY; } @@ -48,6 +62,9 @@ public class RandomOffsetPattern extends AbstractPattern { mutable.mutX((set.getX() + r.nextInt(dx2) - dx)); mutable.mutY((set.getY() + r.nextInt(dy2) - dy)); mutable.mutZ((set.getZ() + r.nextInt(dz2) - dz)); + if (mutable.getY() < minY || mutable.getY() > maxY) { + return false; + } return pattern.apply(extent, get, mutable); } 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 69db01840..3501d1645 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 @@ -11,11 +11,22 @@ import com.sk89q.worldedit.world.block.BaseBlock; public class RelativePattern extends AbstractPattern implements ResettablePattern { private final Pattern pattern; - private BlockVector3 origin; + private final int minY; + private final int maxY; private final MutableBlockVector3 mutable = new MutableBlockVector3(); + private BlockVector3 origin; - public RelativePattern(Pattern pattern) { + /** + * Create a new {@link Pattern} instance + * + * @param pattern pattern to apply + * @param minY min applicable y (inclusive + * @param maxY max applicable y (inclusive + */ + public RelativePattern(Pattern pattern, int minY, int maxY) { this.pattern = pattern; + this.minY = minY; + this.maxY = maxY; } @Override @@ -36,6 +47,9 @@ public class RelativePattern extends AbstractPattern implements ResettablePatter } mutable.mutX(set.getX() - origin.getX()); mutable.mutY(set.getY() - origin.getY()); + if (mutable.getY() < minY || mutable.getY() > maxY) { + return false; + } mutable.mutZ(set.getZ() - origin.getZ()); return pattern.apply(extent, get, mutable); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SaturatePattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SaturatePattern.java index 9796541fc..48c411750 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SaturatePattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SaturatePattern.java @@ -1,13 +1,16 @@ package com.fastasyncworldedit.core.function.pattern; +import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TextureHolder; import com.fastasyncworldedit.core.util.TextureUtil; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; import java.awt.Color; @@ -17,33 +20,53 @@ public class SaturatePattern extends AbstractPattern { private final int color; private final Extent extent; - - public SaturatePattern(Extent extent, int color, TextureHolder texture) { + /** + * Create a new {@link Pattern} instance + * + * @param extent extent to set to + * @param holder {@link TextureHolder} to use to get textures + * @param r red channel, clamped 0 -> 255 + * @param g green channel, clamped 0 -> 255 + * @param b blue channel, clamped 0 -> 255 + * @param a alpha channel, clamped 0 -> 255 + */ + public SaturatePattern(Extent extent, TextureHolder holder, int r, int g, int b, int a) { this.extent = extent; - this.holder = texture; - this.color = new Color(color).getRGB(); + this.holder = holder; + this.color = new Color(MathMan.clamp(r, 0, 255), MathMan.clamp(g, 0, 255), MathMan.clamp(b, 0, 255), MathMan.clamp(a, 0 + , 255)).getRGB(); } @Override public BaseBlock applyBlock(BlockVector3 position) { - BlockType block = extent.getBlock(position).getBlockType(); + BlockType type = extent.getBlock(position).getBlockType(); TextureUtil util = holder.getTextureUtil(); - int currentColor = util.getColor(block); - int newColor = util.multiplyColor(currentColor, color); + int currentColor; + if (type == BlockTypes.GRASS_BLOCK) { + currentColor = holder.getTextureUtil().getColor(extent.getBiome(position)); + } else { + currentColor = holder.getTextureUtil().getColor(type); + } + int newColor = TextureUtil.multiplyColor(currentColor, color); return util.getNearestBlock(newColor).getDefaultState().toBaseBlock(); } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - BlockType block = get.getBlock(extent).getBlockType(); + BlockType type = get.getBlock(extent).getBlockType(); TextureUtil util = holder.getTextureUtil(); - int currentColor = util.getColor(block); + int currentColor; + if (type == BlockTypes.GRASS_BLOCK) { + currentColor = holder.getTextureUtil().getColor(extent.getBiome(get)); + } else { + currentColor = holder.getTextureUtil().getColor(type); + } if (currentColor == 0) { return false; } - int newColor = util.multiplyColor(currentColor, color); + int newColor = TextureUtil.multiplyColor(currentColor, color); BlockType newBlock = util.getNearestBlock(newColor); - if (newBlock.equals(block)) { + if (newBlock.equals(type)) { return false; } return set.setBlock(extent, newBlock.getDefaultState()); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ShadePattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ShadePattern.java index b0034755f..386de836b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ShadePattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ShadePattern.java @@ -1,12 +1,15 @@ package com.fastasyncworldedit.core.function.pattern; +import com.fastasyncworldedit.core.util.TextureHolder; import com.fastasyncworldedit.core.util.TextureUtil; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; import static com.google.common.base.Preconditions.checkNotNull; @@ -16,23 +19,43 @@ public class ShadePattern extends AbstractPattern { private final Extent extent; private final boolean darken; - public ShadePattern(Extent extent, boolean darken, TextureUtil util) { + /** + * Create a new {@link Pattern} instance + * + * @param extent extent to set to + * @param holder {@link TextureHolder} to use for textures + * @param darken if the shade should darken or lighten colours + */ + public ShadePattern(Extent extent, TextureHolder holder, boolean darken) { checkNotNull(extent); this.extent = extent; - this.util = util; + this.util = holder.getTextureUtil(); this.darken = darken; } @Override public BaseBlock applyBlock(BlockVector3 position) { BlockType block = extent.getBlock(position).getBlockType(); - return (darken ? util.getDarkerBlock(block) : util.getLighterBlock(block)).getDefaultState().toBaseBlock(); + BlockType type; + if (block == BlockTypes.GRASS_BLOCK) { + int color = util.getColor(extent.getBiome(position)); + type = (darken ? util.getDarkerBlock(color) : util.getLighterBlock(color)); + } else { + type = (darken ? util.getDarkerBlock(block) : util.getLighterBlock(block)); + } + return type.getDefaultState().toBaseBlock(); } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { BlockType type = get.getBlock(extent).getBlockType(); - BlockType newType = (darken ? util.getDarkerBlock(type) : util.getLighterBlock(type)); + BlockType newType; + if (type == BlockTypes.GRASS_BLOCK) { + int color = util.getColor(extent.getBiome(get)); + newType = (darken ? util.getDarkerBlock(color) : util.getLighterBlock(color)); + } else { + newType = (darken ? util.getDarkerBlock(type) : util.getLighterBlock(type)); + } if (type != newType) { return set.setBlock(extent, newType.getDefaultState()); } 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 0667e100a..a8be79b62 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 @@ -18,6 +18,8 @@ public class SolidRandomOffsetPattern extends AbstractPattern { private final int dx; private final int dy; private final int dz; + private final int minY; + private final int maxY; private final Pattern pattern; private final int dx2; @@ -26,19 +28,23 @@ public class SolidRandomOffsetPattern extends AbstractPattern { private final MutableBlockVector3 mutable; private final SplittableRandom r; - public static boolean[] getTypes() { - boolean[] types = new boolean[BlockTypes.size()]; - for (BlockType type : BlockTypesCache.values) { - types[type.getInternalId()] = type.getMaterial().isSolid(); - } - return types; - } - - public SolidRandomOffsetPattern(Pattern pattern, int dx, int dy, int dz) { + /** + * Create a new {@link Pattern} instance + * + * @param pattern pattern to apply + * @param dx offset x + * @param dy offset y + * @param dz offset z + * @param minY min applicable y (inclusive + * @param maxY max applicable y (inclusive + */ + public SolidRandomOffsetPattern(Pattern pattern, int dx, int dy, int dz, int minY, int maxY) { this.pattern = pattern; this.dx = dx; this.dy = dy; this.dz = dz; + this.minY = minY; + this.maxY = maxY; this.dx2 = dx * 2 + 1; this.dy2 = dy * 2 + 1; @@ -47,6 +53,14 @@ public class SolidRandomOffsetPattern extends AbstractPattern { this.mutable = new MutableBlockVector3(); } + public static boolean[] getTypes() { + boolean[] types = new boolean[BlockTypes.size()]; + for (BlockType type : BlockTypesCache.values) { + types[type.getInternalId()] = type.getMaterial().isSolid(); + } + return types; + } + @Override public BaseBlock applyBlock(BlockVector3 position) { mutable.mutX(position.getX() + r.nextInt(dx2) - dx); @@ -63,6 +77,9 @@ public class SolidRandomOffsetPattern extends AbstractPattern { public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { mutable.mutX(set.getX() + r.nextInt(dx2) - dx); mutable.mutY(set.getY() + r.nextInt(dy2) - dy); + if (mutable.getY() < minY || mutable.getY() > maxY) { + return false; + } mutable.mutZ(set.getZ() + r.nextInt(dz2) - dz); BaseBlock block = pattern.applyBlock(mutable); if (block.getMaterial().isSolid()) { 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 2769c5f05..6b531ccf5 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 @@ -13,13 +13,25 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern { private final Pattern pattern; private final int moves; + private final int minY; + private final int maxY; private final MutableBlockVector3 cur; private final MutableBlockVector3[] buffer; private final MutableBlockVector3[] allowed; - public SurfaceRandomOffsetPattern(Pattern pattern, int distance) { + /** + * Create a new {@link Pattern} instance + * + * @param pattern pattern to apply + * @param distance number of "spreads" to make + * @param minY min applicable y (inclusive + * @param maxY max applicable y (inclusive + */ + public SurfaceRandomOffsetPattern(Pattern pattern, int distance, int minY, int maxY) { this.pattern = pattern; + this.minY = minY; + this.maxY = maxY; this.moves = Math.min(255, distance); cur = new MutableBlockVector3(); this.buffer = new MutableBlockVector3[BreadthFirstSearch.DIAGONAL_DIRECTIONS.length]; @@ -70,12 +82,12 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern { int y = v.getBlockY(); int z = v.getBlockZ(); v.mutY(y + 1); - if (canPassthrough(v)) { + if (y < maxY && canPassthrough(v)) { v.mutY(y); return true; } v.mutY(y - 1); - if (canPassthrough(v)) { + if (y > minY && canPassthrough(v)) { v.mutY(y); return true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/DelegateTextureUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/DelegateTextureUtil.java index 70600635e..ff89310e9 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/DelegateTextureUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/DelegateTextureUtil.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.util; +import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockType; import java.awt.image.BufferedImage; @@ -22,11 +23,6 @@ public class DelegateTextureUtil extends TextureUtil { return parent.getNearestBlock(color); } - @Override - public BlockType getNearestBlock(BlockType block) { - return parent.getNearestBlock(block); - } - @Override public BlockType getNextNearestBlock(int color) { return parent.getNextNearestBlock(color); @@ -47,11 +43,26 @@ public class DelegateTextureUtil extends TextureUtil { return parent.getDarkerBlock(block); } + @Override + public BlockType getLighterBlock(final int color) { + return parent.getLighterBlock(color); + } + + @Override + public BlockType getDarkerBlock(final int color) { + return parent.getDarkerBlock(color); + } + @Override public int getColor(BlockType block) { return parent.getColor(block); } + @Override + public int getColor(final BiomeType biome) { + return parent.getColor(biome); + } + @Override public boolean getIsBlockCloserThanBiome(char[] blockAndBiomeIdOutput, int color, int biomePriority) { return parent.getIsBlockCloserThanBiome(blockAndBiomeIdOutput, color, biomePriority); @@ -77,11 +88,6 @@ public class DelegateTextureUtil extends TextureUtil { return parent.getFolder(); } - @Override - public int combineTransparency(int top, int bottom) { - return parent.combineTransparency(top, bottom); - } - @Override public void calculateLayerArrays() { parent.calculateLayerArrays(); @@ -92,11 +98,6 @@ public class DelegateTextureUtil extends TextureUtil { parent.loadModTextures(); } - @Override - public int multiplyColor(int c1, int c2) { - return parent.multiplyColor(c1, c2); - } - @Override public BlockType getNearestBlock(BlockType block, boolean darker) { return parent.getNearestBlock(block, darker); @@ -112,19 +113,4 @@ public class DelegateTextureUtil extends TextureUtil { return parent.hasAlpha(color); } - @Override - public long colorDistance(int c1, int c2) { - return parent.colorDistance(c1, c2); - } - - @Override - public long colorDistance(int red1, int green1, int blue1, int c2) { - return parent.colorDistance(red1, green1, blue1, c2); - } - - @Override - public long getDistance(BufferedImage image, int c1) { - return parent.getDistance(image, c1); - } - } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java index 338dbf014..ead803939 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java @@ -11,15 +11,16 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; -import com.sk89q.worldedit.world.registry.BlockMaterial; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArraySet; import it.unimi.dsi.fastutil.longs.LongArrayList; import org.apache.logging.log4j.Logger; + import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.BufferedInputStream; @@ -32,24 +33,18 @@ import java.io.InputStreamReader; import java.lang.reflect.Type; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; import java.security.AccessControlException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Enumeration; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import static org.apache.logging.log4j.LogManager.getLogger; -// TODO FIXME public class TextureUtil implements TextureHolder { private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -63,6 +58,271 @@ public class TextureUtil implements TextureHolder { } private final File folder; + private final BiomeColor[] biomes = new BiomeColor[]{ + // ID Name Temperature, rainfall, grass, foliage colors + // - note: the colors here are just placeholders, they are computed in the program + new BiomeColor(0, "ocean", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), + // default values of temp and rain + new BiomeColor(1, "plains", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(2, "desert", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(3, "mountains", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), + new BiomeColor(4, "forest", 0.7f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(5, "taiga", 0.25f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(6, "swamp", 0.8f, 0.9f, 0x92BD59, 0x77AB2F), + new BiomeColor(7, "river", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), + // default values of temp and rain + new BiomeColor(8, "nether", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(9, "the_end", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), + // default values of temp and rain + new BiomeColor(10, "frozen_ocean", 0.0f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(11, "frozen_river", 0.0f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(12, "snowy_tundra", 0.0f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(13, "snowy_mountains", 0.0f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(14, "mushroom_fields", 0.9f, 1.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(15, "mushroom_field_shore", 0.9f, 1.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(16, "beach", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(17, "desert_hills", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(18, "wooded_hills", 0.7f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(19, "taiga_hills", 0.25f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(20, "mountain_edge", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), + new BiomeColor(21, "jungle", 0.95f, 0.9f, 0x92BD59, 0x77AB2F), + new BiomeColor(22, "jungle_hills", 0.95f, 0.9f, 0x92BD59, 0x77AB2F), + new BiomeColor(23, "jungle_edge", 0.95f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(24, "deep_ocean", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(25, "stone_shore", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), + new BiomeColor(26, "snowy_beach", 0.05f, 0.3f, 0x92BD59, 0x77AB2F), + new BiomeColor(27, "birch_forest", 0.6f, 0.6f, 0x92BD59, 0x77AB2F), + new BiomeColor(28, "birch_forest_hills", 0.6f, 0.6f, 0x92BD59, 0x77AB2F), + new BiomeColor(29, "dark_forest", 0.7f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(30, "snowy_taiga", -0.5f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(31, "snowy_taiga_hills", -0.5f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(32, "giant_tree_taiga", 0.3f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(33, "giant_tree_taiga_hills", 0.3f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(34, "wooded_mountains", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), + new BiomeColor(35, "savanna", 1.2f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(36, "savanna_plateau", 1.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(37, "badlands", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(38, "wooded_badlands_plateau", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(39, "badlands_plateau", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(40, "small_end_islands", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(41, "end_midlands", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(42, "end_highlands", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(43, "end_barrens", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(44, "warm_ocean", 0.8f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(45, "lukewarm_ocean", 0.8f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(46, "cold_ocean", 0.8f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(47, "deep_warm_ocean", 0.8f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(48, "deep_lukewarm_ocean", 0.8f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(49, "deep_cold_ocean", 0.8f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(50, "deep_frozen_ocean", 0.8f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(51, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(52, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(53, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(54, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(55, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(56, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(57, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(58, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(59, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(60, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(61, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(62, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(63, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(64, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(65, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(66, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(67, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(68, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(69, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(70, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(71, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(72, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(73, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(74, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(75, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(76, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(77, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(78, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(79, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(80, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(81, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(82, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(83, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(84, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(85, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(86, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(87, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(88, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(89, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(90, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(91, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(92, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(93, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(94, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(95, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(96, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(97, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(98, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(99, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(100, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(101, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(102, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(103, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(104, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(105, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(106, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(107, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(108, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(109, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(110, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(111, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(112, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(113, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(114, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(115, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(116, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(117, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(118, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(119, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(120, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(121, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(122, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(123, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(124, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(125, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(126, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(127, "the_void", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), + // default values of temp and rain; also, no height differences + new BiomeColor(128, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(129, "sunflower_plains", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(130, "desert_lakes", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(131, "gravelly_mountains", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), + new BiomeColor(132, "flower_forest", 0.7f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(133, "taiga_mountains", 0.25f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(134, "swamp_hills", 0.8f, 0.9f, 0x92BD59, 0x77AB2F), + new BiomeColor(135, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(136, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(137, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(138, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(139, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(140, "ice_spikes", 0.0f, 0.5f, 0x92BD59, 0x77AB2F), + new BiomeColor(141, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(142, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(143, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(144, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(145, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(146, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(147, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(148, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(149, "modified_jungle", 0.95f, 0.9f, 0x92BD59, 0x77AB2F), + new BiomeColor(150, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(151, "modified_jungle_edge", 0.95f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(152, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(153, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(154, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(155, "tall_birch_forest", 0.6f, 0.6f, 0x92BD59, 0x77AB2F), + new BiomeColor(156, "tall_birch_hills", 0.6f, 0.6f, 0x92BD59, 0x77AB2F), + new BiomeColor(157, "dark_forest_hills", 0.7f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(158, "snowy_taiga_mountains", -0.5f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(159, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(160, "giant_spruce_taiga", 0.25f, 0.8f, 0x92BD59, 0x77AB2F), + // special exception, temperature not 0.3 + new BiomeColor(161, "giant_spruce_taiga_hills", 0.25f, 0.8f, 0x92BD59, 0x77AB2F), + new BiomeColor(162, "gravelly_mountains+", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), + new BiomeColor(163, "shattered_savanna", 1.1f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(164, "shattered_savanna_plateau", 1.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(165, "eroded_badlands", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(166, "modified_wooded_badlands_plateau", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(167, "modified_badlands_plateau", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(168, "bamboo_jungle", 0.95f, 0.9f, 0x92BD59, 0x77AB2F), + new BiomeColor(168, "bamboo_jungle_hills", 0.95f, 0.9f, 0x92BD59, 0x77AB2F), + new BiomeColor(170, "soul_sand_valley", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(171, "crimson_forest", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(172, "warped_forest", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(173, "basalt_deltas", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), + new BiomeColor(174, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(175, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(176, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(177, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(178, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(179, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(180, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(181, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(182, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(183, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(184, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(185, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(186, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(187, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(188, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(189, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(190, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(191, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(192, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(193, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(194, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(195, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(196, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(197, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(198, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(199, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(200, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(201, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(202, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(203, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(204, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(205, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(206, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(207, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(208, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(209, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(210, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(211, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(212, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(213, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(214, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(215, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(216, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(217, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(218, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(219, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(220, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(221, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(222, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(223, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(224, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(225, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(226, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(227, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(228, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(229, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(230, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(231, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(232, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(233, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(234, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(235, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(236, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(237, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(238, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(239, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(240, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(241, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(242, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(243, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(244, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(245, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(246, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(247, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(248, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(249, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(250, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(251, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(252, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(253, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(254, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), + new BiomeColor(255, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F)}; + private final BlockType[] layerBuffer = new BlockType[2]; protected int[] blockColors = new int[BlockTypes.size()]; protected long[] blockDistance = new long[BlockTypes.size()]; protected long[] distances; @@ -76,289 +336,28 @@ public class TextureUtil implements TextureHolder { * https://github.com/erich666/Mineways/blob/master/Win/biomes.cpp */ protected BiomeColor[] validBiomes; - private final BiomeColor[] biomes = new BiomeColor[] { - // ID Name Temperature, rainfall, grass, foliage colors - // - note: the colors here are just placeholders, they are computed in the program - new BiomeColor(0, "ocean", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), - // default values of temp and rain - new BiomeColor(1, "plains", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(2, "desert", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(3, "mountains", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), - new BiomeColor(4, "forest", 0.7f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(5, "taiga", 0.25f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(6, "swamp", 0.8f, 0.9f, 0x92BD59, 0x77AB2F), - new BiomeColor(7, "river", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), - // default values of temp and rain - new BiomeColor(8, "nether", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(9, "the_end", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), - // default values of temp and rain - new BiomeColor(10, "frozen_ocean", 0.0f, 0.5f, 0x92BD59, 0x77AB2F), - new BiomeColor(11, "frozen_river", 0.0f, 0.5f, 0x92BD59, 0x77AB2F), - new BiomeColor(12, "snowy_tundra", 0.0f, 0.5f, 0x92BD59, 0x77AB2F), - new BiomeColor(13, "snowy_mountains", 0.0f, 0.5f, 0x92BD59, 0x77AB2F), - new BiomeColor(14, "mushroom_fields", 0.9f, 1.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(15, "mushroom_field_shore", 0.9f, 1.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(16, "beach", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(17, "desert_hills", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(18, "wooded_hills", 0.7f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(19, "taiga_hills", 0.25f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(20, "mountain_edge", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), - new BiomeColor(21, "jungle", 0.95f, 0.9f, 0x92BD59, 0x77AB2F), - new BiomeColor(22, "jungle_hills", 0.95f, 0.9f, 0x92BD59, 0x77AB2F), - new BiomeColor(23, "jungle_edge", 0.95f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(24, "deep_ocean", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), - new BiomeColor(25, "stone_shore", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), - new BiomeColor(26, "snowy_beach", 0.05f, 0.3f, 0x92BD59, 0x77AB2F), - new BiomeColor(27, "birch_forest", 0.6f, 0.6f, 0x92BD59, 0x77AB2F), - new BiomeColor(28, "birch_forest_hills", 0.6f, 0.6f, 0x92BD59, 0x77AB2F), - new BiomeColor(29, "dark_forest", 0.7f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(30, "snowy_taiga", -0.5f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(31, "snowy_taiga_hills", -0.5f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(32, "giant_tree_taiga", 0.3f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(33, "giant_tree_taiga_hills", 0.3f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(34, "wooded_mountains", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), - new BiomeColor(35, "savanna", 1.2f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(36, "savanna_plateau", 1.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(37, "badlands", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(38, "wooded_badlands_plateau", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(39, "badlands_plateau", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(40, "small_end_islands", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(41, "end_midlands", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(42, "end_highlands", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(43, "end_barrens", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(44, "warm_ocean", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(45, "lukewarm_ocean", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(46, "cold_ocean", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(47, "deep_warm_ocean", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(48, "deep_lukewarm_ocean", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(49, "deep_cold_ocean", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(50, "deep_frozen_ocean", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(51, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(52, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(53, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(54, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(55, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(56, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(57, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(58, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(59, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(60, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(61, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(62, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(63, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(64, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(65, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(66, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(67, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(68, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(69, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(70, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(71, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(72, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(73, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(74, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(75, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(76, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(77, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(78, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(79, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(80, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(81, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(82, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(83, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(84, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(85, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(86, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(87, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(88, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(89, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(90, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(91, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(92, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(93, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(94, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(95, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(96, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(97, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(98, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(99, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(100, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(101, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(102, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(103, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(104, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(105, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(106, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(107, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(108, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(109, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(110, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(111, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(112, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(113, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(114, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(115, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(116, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(117, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(118, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(119, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(120, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(121, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(122, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(123, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(124, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(125, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(126, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(127, "the_void", 0.5f, 0.5f, 0x92BD59, 0x77AB2F), - // default values of temp and rain; also, no height differences - new BiomeColor(128, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(129, "sunflower_plains", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(130, "desert_lakes", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(131, "gravelly_mountains", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), - new BiomeColor(132, "flower_forest", 0.7f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(133, "taiga_mountains", 0.25f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(134, "swamp_hills", 0.8f, 0.9f, 0x92BD59, 0x77AB2F), - new BiomeColor(135, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(136, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(137, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(138, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(139, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(140, "ice_spikes", 0.0f, 0.5f, 0x92BD59, 0x77AB2F), - new BiomeColor(141, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(142, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(143, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(144, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(145, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(146, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(147, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(148, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(149, "modified_jungle", 0.95f, 0.9f, 0x92BD59, 0x77AB2F), - new BiomeColor(150, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(151, "modified_jungle_edge", 0.95f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(152, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(153, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(154, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(155, "tall_birch_forest", 0.6f, 0.6f, 0x92BD59, 0x77AB2F), - new BiomeColor(156, "tall_birch_hills", 0.6f, 0.6f, 0x92BD59, 0x77AB2F), - new BiomeColor(157, "dark_forest_hills", 0.7f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(158, "snowy_taiga_mountains", -0.5f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(159, "Unknown", -0.5f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(160, "giant_spruce_taiga", 0.25f, 0.8f, 0x92BD59, 0x77AB2F), - // special exception, temperature not 0.3 - new BiomeColor(161, "giant_spruce_taiga_hills", 0.25f, 0.8f, 0x92BD59, 0x77AB2F), - new BiomeColor(162, "modified_gravelly_mountains", 0.2f, 0.3f, 0x92BD59, 0x77AB2F), - new BiomeColor(163, "shattered_savanna", 1.1f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(164, "shattered_savanna_plateau", 1.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(165, "eroded_badlands", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(166, "modified_wooded_badlands_plateau", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(167, "modified_badlands_plateau", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(168, "bamboo_jungle", 0.95f, 0.9f, 0x92BD59, 0x77AB2F), - new BiomeColor(169, "bamboo_jungle_hills", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(170, "Unknown Biome", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(171, "Unknown Biome", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(172, "Unknown Biome", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(173, "Unknown Biome", 2.0f, 0.0f, 0x92BD59, 0x77AB2F), - new BiomeColor(174, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(175, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(176, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(177, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(178, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(179, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(180, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(181, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(182, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(183, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(184, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(185, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(186, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(187, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(188, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(189, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(190, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(191, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(192, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(193, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(194, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(195, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(196, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(197, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(198, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(199, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(200, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(201, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(202, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(203, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(204, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(205, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(206, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(207, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(208, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(209, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(210, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(211, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(212, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(213, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(214, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(215, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(216, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(217, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(218, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(219, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(220, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(221, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(222, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(223, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(224, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(225, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(226, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(227, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(228, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(229, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(230, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(231, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(232, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(233, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(234, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(235, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(236, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(237, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(238, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(239, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(240, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(241, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(242, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(243, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(244, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(245, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(246, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(247, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(248, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(249, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(250, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(251, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(252, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(253, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(254, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F), - new BiomeColor(255, "Unknown Biome", 0.8f, 0.4f, 0x92BD59, 0x77AB2F)}; - private final BlockType[] layerBuffer = new BlockType[2]; + /** + * Do not use. Use {@link Fawe#getTextureUtil()} + */ public TextureUtil() throws FileNotFoundException { this(MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.TEXTURES)); } + /** + * Do not use. Use {@link Fawe#getTextureUtil()} + */ public TextureUtil(File folder) throws FileNotFoundException { this.folder = folder; if (!folder.exists()) { try { LOGGER.info("Downloading asset jar from Mojang, please wait..."); - new File(Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/" + "/.minecraft/versions/") - .mkdirs(); + new File(Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/").mkdirs(); try (BufferedInputStream in = new BufferedInputStream( - new URL("https://launcher.mojang.com/v1/objects/8d9b65467c7913fcf6f5b2e729d44a1e00fde150/client.jar") - .openStream()); - FileOutputStream fileOutputStream = new FileOutputStream( - Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/" - + "/.minecraft/versions/1.17.1.jar")) { + new URL("https://launcher.mojang.com/v1/objects/8d9b65467c7913fcf6f5b2e729d44a1e00fde150/client.jar") + .openStream()); + FileOutputStream fileOutputStream = new FileOutputStream( + Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/1.17.1.jar")) { byte[] dataBuffer = new byte[1024]; int bytesRead; while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { @@ -367,14 +366,16 @@ public class TextureUtil implements TextureHolder { LOGGER.info("Asset jar down has been downloaded successfully."); } catch (IOException e) { LOGGER.error( - "Could not download version jar. Please do so manually by creating a `FastAsyncWorldEdit/textures` folder with `.minecraft/versions` jar in it."); + "Could not download version jar. Please do so manually by creating a `FastAsyncWorldEdit/textures` " + + "folder with a `.minecraft/versions` jar in it."); LOGGER.error("If the file exists, please make sure the server has read access to the directory."); } } catch (AccessControlException e) { LOGGER.error( - "Could not download asset jar. It's likely your file permission are setup improperly and do not allow fetching data from the Mojang servers."); + "Could not download asset jar. It's likely your file permission are setup improperly and do not allow fetching data from the Mojang servers."); LOGGER.error( - "Please create the following folder manually: `FastAsyncWorldEdit/textures` with `.minecraft/versions` jar in it."); + "Please create the following folder manually: `FastAsyncWorldEdit/textures` with a `" + + ".minecraft/versions` jar in it."); } } @@ -423,22 +424,155 @@ public class TextureUtil implements TextureHolder { } int factor1 = FACTORS[total1]; int factor2 = FACTORS[total2]; - long r = (512 * (red1 * factor1 - red2 * factor2)) >> 10; - long g = (green1 * factor1 - green2 * factor2); - long b = (767 * (blue1 * factor1 - blue2 * factor2)) >> 10; + long r = (512 * ((long) red1 * factor1 - (long) red2 * factor2)) >> 10; + long g = ((long) green1 * factor1 - (long) green2 * factor2); + long b = (767 * ((long) blue1 * factor1 - (long) blue2 * factor2)) >> 10; return (int) ((r * r + g * g + b * b) >> 25); } - @Override public TextureUtil getTextureUtil() { + protected static long colorDistance(int c1, int c2) { + int red1 = (c1 >> 16) & 0xFF; + int green1 = (c1 >> 8) & 0xFF; + int blue1 = (c1) & 0xFF; + return colorDistance(red1, green1, blue1, c2); + } + + private static long colorDistance(int red1, int green1, int blue1, int c2) { + int red2 = (c2 >> 16) & 0xFF; + int green2 = (c2 >> 8) & 0xFF; + int blue2 = (c2) & 0xFF; + int rmean = (red1 + red2) >> 1; + int r = red1 - red2; + int g = green1 - green2; + int b = blue1 - blue2; + int hd = hueDistance(red1, green1, blue1, red2, green2, blue2); + return (((long) (512 + rmean) * r * r) >> 8) + 4L * g * g + (((long) (767 - rmean) * b * b) >> 8) + ((long) hd * hd); + } + + /** + * Combine two colors by multipling + * + * @param c1 color 1 + * @param c2 color 2 + * @return new color + */ + public static int multiplyColor(int c1, int c2) { + int alpha1 = (c1 >> 24) & 0xFF; + int alpha2 = (c2 >> 24) & 0xFF; + int red1 = (c1 >> 16) & 0xFF; + int green1 = (c1 >> 8) & 0xFF; + int blue1 = (c1) & 0xFF; + int red2 = (c2 >> 16) & 0xFF; + int green2 = (c2 >> 8) & 0xFF; + int blue2 = (c2) & 0xFF; + int red = ((red1 * red2)) / 255; + int green = ((green1 * green2)) / 255; + int blue = ((blue1 * blue2)) / 255; + int alpha = ((alpha1 * alpha2)) / 255; + return (alpha << 24) + (red << 16) + (green << 8) + (blue); + } + + /** + * Combine two colors by averaging + * + * @param c1 color 1 + * @param c2 color 2 + * @return new color + */ + public static int averageColor(int c1, int c2) { + int alpha1 = (c1 >> 24) & 0xFF; + int alpha2 = (c2 >> 24) & 0xFF; + int red1 = (c1 >> 16) & 0xFF; + int green1 = (c1 >> 8) & 0xFF; + int blue1 = (c1) & 0xFF; + int red2 = (c2 >> 16) & 0xFF; + int green2 = (c2 >> 8) & 0xFF; + int blue2 = (c2) & 0xFF; + int red = ((red1 + red2)) >> 1; + int green = ((green1 + green2)) >> 1; + int blue = ((blue1 + blue2)) >> 1; + int alpha = ((alpha1 + alpha2)) >> 1; + return (alpha << 24) + (red << 16) + (green << 8) + (blue); + } + + /** + * Combine multiple colors by multipling + * + * @param colors colors + * @return new color + */ + public static int averageColor(int... colors) { + int alpha = 0; + int red = 0; + int green = 0; + int blue = 0; + for (int c : colors) { + alpha += (c >> 24) & 0xFF; + red += (c >> 16) & 0xFF; + green += (c >> 8) & 0xFF; + blue += (c) & 0xFF; + } + int num = colors.length; + alpha /= num; + red /= num; + green /= num; + blue /= num; + return (alpha << 24) + (red << 16) + (green << 8) + (blue); + } + + /** + * Assumes the top layer is a transparent color and the bottom is opaque + */ + public static int combineTransparency(int top, int bottom) { + int alpha1 = (top >> 24) & 0xFF; + int alpha2 = 255 - alpha1; + int red1 = (top >> 16) & 0xFF; + int green1 = (top >> 8) & 0xFF; + int blue1 = (top) & 0xFF; + int red2 = (bottom >> 16) & 0xFF; + int green2 = (bottom >> 8) & 0xFF; + int blue2 = (bottom) & 0xFF; + int red = ((red1 * alpha1) + (red2 * alpha2)) / 255; + int green = ((green1 * alpha1) + (green2 * alpha2)) / 255; + int blue = ((blue1 * alpha1) + (blue2 * alpha2)) / 255; + return (red << 16) + (green << 8) + (blue) + (255 << 24); + } + + private static long getDistance(BufferedImage image, int c1) { + long totalDistSqr = 0; + int width = image.getWidth(); + int height = image.getHeight(); + int area = width * height; + int red1 = (c1 >> 16) & 0xFF; + int green1 = (c1 >> 8) & 0xFF; + int blue1 = (c1) & 0xFF; + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + int c2 = image.getRGB(x, y); + long distance = colorDistance(red1, green1, blue1, c2); + totalDistSqr += distance * distance; + } + } + return totalDistSqr / area; + } + + @Override + public TextureUtil getTextureUtil() { return this; } + /** + * Get the block most closely matching a color based on the block's average color + * + * @param color color to match + * @return matching block + */ public BlockType getNearestBlock(int color) { long min = Long.MAX_VALUE; int closest = 0; int red1 = (color >> 16) & 0xFF; int green1 = (color >> 8) & 0xFF; - int blue1 = (color >> 0) & 0xFF; + int blue1 = (color) & 0xFF; int alpha = (color >> 24) & 0xFF; for (int i = 0; i < validColors.length; i++) { int other = validColors[i]; @@ -456,20 +590,18 @@ public class TextureUtil implements TextureHolder { return BlockTypes.get(closest); } - public BlockType getNearestBlock(BlockType block) { - int color = getColor(block); - if (color == 0) { - return null; - } - return getNextNearestBlock(color); - } - + /** + * Get the block most closely matching a color, without matching the color, based on the block's average color + * + * @param color color to match + * @return matching block + */ public BlockType getNextNearestBlock(int color) { long min = Long.MAX_VALUE; int closest = 0; int red1 = (color >> 16) & 0xFF; int green1 = (color >> 8) & 0xFF; - int blue1 = (color >> 0) & 0xFF; + int blue1 = (color) & 0xFF; int alpha = (color >> 24) & 0xFF; for (int i = 0; i < validColors.length; i++) { int other = validColors[i]; @@ -495,7 +627,7 @@ public class TextureUtil implements TextureHolder { long min = Long.MAX_VALUE; int red1 = (color >> 16) & 0xFF; int green1 = (color >> 8) & 0xFF; - int blue1 = (color >> 0) & 0xFF; + int blue1 = (color) & 0xFF; int alpha = (color >> 24) & 0xFF; for (int i = 0; i < validLayerColors.length; i++) { int other = validLayerColors[i]; @@ -512,23 +644,80 @@ public class TextureUtil implements TextureHolder { return layerBuffer; } + /** + * Get the next lightest block + * + * @param block input block + * @return next lightest block + */ public BlockType getLighterBlock(BlockType block) { return getNearestBlock(block, false); } + /** + * Get the next darkest block + * + * @param block input block + * @return next darkest block + */ public BlockType getDarkerBlock(BlockType block) { return getNearestBlock(block, true); } + /** + * Get the next lightest block + * + * @param color input color + * @return next lightest block + */ + public BlockType getLighterBlock(int color) { + return getNearestBlock(color, false); + } + + /** + * Get the next darkest block + * + * @param color input color + * @return next darkest block + */ + public BlockType getDarkerBlock(int color) { + return getNearestBlock(color, true); + } + + /** + * Get the integer representation of a block's RGBA color. + * + * @param block input block + * @return integer RGBA color + */ public int getColor(BlockType block) { + if (block == BlockTypes.GRASS_BLOCK) { + return validBiomes[0].grassCombined; + } return blockColors[block.getInternalId()]; } + /** + * Get the integer representation of a biomes's RGBA color when applied to grass. + * + * @param biome input biome + * @return integer RGBA color + */ + public int getColor(BiomeType biome) { + return validBiomes[biome.getInternalId()].grassCombined; + } + + /** + * Get the {@link BiomeColor} entry from a biome's ID + * + * @param biome biome id + * @return the {@link BiomeColor} entry + */ public BiomeColor getBiome(int biome) { return biomes[biome]; } - public boolean getIsBlockCloserThanBiome(char[] blockAndBiomeIdOutput, int color, int biomePriority) { + protected boolean getIsBlockCloserThanBiome(char[] blockAndBiomeIdOutput, int color, int biomePriority) { BlockType block = getNearestBlock(color); TextureUtil.BiomeColor biome = getNearestBiome(color); int blockColor = getColor(block); @@ -537,13 +726,13 @@ public class TextureUtil implements TextureHolder { return colorDistance(biome.grassCombined, color) - biomePriority > colorDistance(blockColor, color); } - public int getBiomeMix(int[] biomeIdsOutput, int color) { + protected int getBiomeMix(int[] biomeIdsOutput, int color) { long closest = Long.MAX_VALUE; int closestAverage = Integer.MAX_VALUE; long min = Long.MAX_VALUE; int red1 = (color >> 16) & 0xFF; int green1 = (color >> 8) & 0xFF; - int blue1 = (color >> 0) & 0xFF; + int blue1 = (color) & 0xFF; int alpha = (color >> 24) & 0xFF; for (int i = 0; i < validMixBiomeColors.length; i++) { int other = validMixBiomeColors[i]; @@ -556,12 +745,18 @@ public class TextureUtil implements TextureHolder { } } } - biomeIdsOutput[0] = (int) ((closest >> 0) & 0xFF); + biomeIdsOutput[0] = (int) ((closest) & 0xFF); biomeIdsOutput[1] = (int) ((closest >> 8) & 0xFF); biomeIdsOutput[2] = (int) ((closest >> 16) & 0xFF); return closestAverage; } + /** + * Get the biome most closely matching a color based on the block's average color + * + * @param color color to match + * @return matching block + */ public BiomeColor getNearestBiome(int color) { int grass = blockColors[BlockTypes.GRASS_BLOCK.getInternalId()]; if (grass == 0) { @@ -571,7 +766,7 @@ public class TextureUtil implements TextureHolder { long min = Long.MAX_VALUE; int red = (color >> 16) & 0xFF; int green = (color >> 8) & 0xFF; - int blue = (color >> 0) & 0xFF; + int blue = (color) & 0xFF; for (BiomeColor biome : validBiomes) { long distance = colorDistance(red, green, blue, biome.grassCombined); if (distance < min) { @@ -582,17 +777,10 @@ public class TextureUtil implements TextureHolder { return closest; } - public File getFolder() { + protected File getFolder() { return folder; } - public long colorDistance(int c1, int c2) { - int red1 = (c1 >> 16) & 0xFF; - int green1 = (c1 >> 8) & 0xFF; - int blue1 = (c1 >> 0) & 0xFF; - return colorDistance(red1, green1, blue1, c2); - } - private BufferedImage readImage(ZipFile zipFile, String name) throws IOException { ZipEntry entry = getEntry(zipFile, name); if (entry != null) { @@ -619,56 +807,35 @@ public class TextureUtil implements TextureHolder { if (folder.exists()) { // Get all the jar files File[] files = folder.listFiles((dir, name) -> name.endsWith(".jar")); - for (BlockType blockType : BlockTypesCache.values) { - BlockMaterial material = blockType.getMaterial(); - if (!material.isSolid() || !material.isFullCube()) { - continue; - } - int color = material.getMapColor(); - if (color != 0) { - colorMap.put(blockType.getInternalId(), (Integer) color); - } - } if (files.length == 0) { - new File(Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/" + "/.minecraft/versions/") - .mkdirs(); + new File(Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/") + .mkdirs(); try (BufferedInputStream in = new BufferedInputStream( - new URL("https://launcher.mojang.com/v1/objects/8d9b65467c7913fcf6f5b2e729d44a1e00fde150/client.jar") - .openStream()); - FileOutputStream fileOutputStream = new FileOutputStream( - Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/" - + "/.minecraft/versions/1.17.1.jar")) { + new URL("https://launcher.mojang.com/v1/objects/8d9b65467c7913fcf6f5b2e729d44a1e00fde150/client.jar") + .openStream()); + FileOutputStream fileOutputStream = new FileOutputStream( + Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/1.17.1.jar")) { byte[] dataBuffer = new byte[1024]; int bytesRead; while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { fileOutputStream.write(dataBuffer, 0, bytesRead); } + fileOutputStream.close(); + files = folder.listFiles((dir, name) -> name.endsWith(".jar")); } catch (IOException e) { LOGGER.error( - "Could not download version jar. Please do so manually by creating a `FastAsyncWorldEdit/textures` folder with `.minecraft/versions` jar or mods in it."); + "Could not download version jar. Please do so manually by creating a `FastAsyncWorldEdit/textures` " + + "folder with a `.minecraft/versions` jar or mods in it."); LOGGER.error("If the file exists, please make sure the server has read access to the directory."); } - } else { + } + if ((files.length > 0)) { for (File file : files) { ZipFile zipFile = new ZipFile(file); // Get all the groups in the current jar // The vanilla textures are in `assets/minecraft` // A jar may contain textures for multiple mods - Enumeration entries = zipFile.entries(); - Set mods = new HashSet<>(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - String name = entry.getName(); - Path path = Paths.get(name); - if (path.startsWith("assets" + File.separator)) { - String[] split = path.toString().split(Pattern.quote(File.separator)); - if (split.length > 1) { - String modId = split[1]; - mods.add(modId); - } - } - } String modelsDir = "assets/%1$s/models/block/%2$s.json"; String texturesDir = "assets/%1$s/textures/%2$s.png"; @@ -679,18 +846,24 @@ public class TextureUtil implements TextureHolder { if (!blockType.getMaterial().isFullCube() || blockType.getId().toLowerCase().contains("shulker")) { continue; } + switch (blockType.getId().toLowerCase(Locale.ROOT)) { + case "slime_block": + case "honey_block": + case "mob_spawner": + case "spawner": + continue; + } int combined = blockType.getInternalId(); String id = blockType.getId(); String[] split = id.split(":", 2); String name = split.length == 1 ? id : split[1]; String nameSpace = split.length == 1 ? "" : split[0]; - Map texturesMap = new ConcurrentHashMap<>(); // Read models String modelFileName = String.format(modelsDir, nameSpace, name); ZipEntry entry = getEntry(zipFile, modelFileName); if (entry == null) { - getLogger(TextureUtil.class).error("Cannot find {} in {}", modelFileName, file); + LOGGER.error("Cannot find {} in {}", modelFileName, file); continue; } @@ -728,7 +901,7 @@ public class TextureUtil implements TextureHolder { BufferedImage image = readImage(zipFile, textureFileName); if (image == null) { - getLogger(TextureUtil.class).error("Cannot find {}", textureFileName); + LOGGER.error("Cannot find {}", textureFileName); continue; } int color = ImageUtil.getColor(image); @@ -738,15 +911,16 @@ public class TextureUtil implements TextureHolder { } Integer grass = null; { - String grassFileName = String.format(texturesDir, "minecraft", "grass_block_top"); + String grassFileName = String.format(texturesDir, "minecraft", "block/grass_block_top"); BufferedImage image = readImage(zipFile, grassFileName); if (image != null) { grass = ImageUtil.getColor(image); } } if (grass != null) { + colorMap.put(BlockTypes.GRASS_BLOCK.getInternalId(), grass); // assets\minecraft\textures\colormap - ZipEntry grassEntry = getEntry(zipFile, "assets/minecraft/textures/colormap/grass_block.png"); + ZipEntry grassEntry = getEntry(zipFile, "assets/minecraft/textures/colormap/grass.png"); if (grassEntry != null) { try (InputStream is = zipFile.getInputStream(grassEntry)) { BufferedImage image = ImageIO.read(is); @@ -774,7 +948,7 @@ public class TextureUtil implements TextureHolder { biomes[167].grass = 0x90814D + (255 << 24); List valid = new ArrayList<>(); for (BiomeColor biome : biomes) { - // biome.grass = multiplyColor(biome.grass, grass); + //biome.grass = multiplyColor(biome.grass, grass); if (biome.grass != 0 && !biome.name.equalsIgnoreCase("Unknown Biome")) { valid.add(biome); } @@ -789,8 +963,6 @@ public class TextureUtil implements TextureHolder { uniqueColors.add(color); } } - int count = 0; - int count2 = 0; uniqueBiomesColors.clear(); LongArrayList layerIds = new LongArrayList(); @@ -803,9 +975,8 @@ public class TextureUtil implements TextureHolder { BiomeColor c3 = uniqueColors.get(k); int average = averageColor(c1.grass, c2.grass, c3.grass); if (uniqueBiomesColors.add(average)) { - count++; layerColors.add(average); - layerIds.add((c1.id) + (c2.id << 8) + (c3.id << 16)); + layerIds.add((c1.id) + ((long) c2.id << 8) + ((long) c3.id << 16)); } } } @@ -819,7 +990,7 @@ public class TextureUtil implements TextureHolder { } } - // Close the file + // Close the file zipFile.close(); } } @@ -848,75 +1019,6 @@ public class TextureUtil implements TextureHolder { calculateLayerArrays(); } - public int multiplyColor(int c1, int c2) { - int alpha1 = (c1 >> 24) & 0xFF; - int alpha2 = (c2 >> 24) & 0xFF; - int red1 = (c1 >> 16) & 0xFF; - int green1 = (c1 >> 8) & 0xFF; - int blue1 = (c1 >> 0) & 0xFF; - int red2 = (c2 >> 16) & 0xFF; - int green2 = (c2 >> 8) & 0xFF; - int blue2 = (c2 >> 0) & 0xFF; - int red = ((red1 * red2)) / 255; - int green = ((green1 * green2)) / 255; - int blue = ((blue1 * blue2)) / 255; - int alpha = ((alpha1 * alpha2)) / 255; - return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0); - } - - public int averageColor(int c1, int c2) { - int alpha1 = (c1 >> 24) & 0xFF; - int alpha2 = (c2 >> 24) & 0xFF; - int red1 = (c1 >> 16) & 0xFF; - int green1 = (c1 >> 8) & 0xFF; - int blue1 = (c1 >> 0) & 0xFF; - int red2 = (c2 >> 16) & 0xFF; - int green2 = (c2 >> 8) & 0xFF; - int blue2 = (c2 >> 0) & 0xFF; - int red = ((red1 + red2)) >> 1; - int green = ((green1 + green2)) >> 1; - int blue = ((blue1 + blue2)) >> 1; - int alpha = ((alpha1 + alpha2)) >> 1; - return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0); - } - - public int averageColor(int... colors) { - int alpha = 0; - int red = 0; - int green = 0; - int blue = 0; - for (int c : colors) { - alpha += (c >> 24) & 0xFF; - red += (c >> 16) & 0xFF; - green += (c >> 8) & 0xFF; - blue += (c >> 0) & 0xFF; - } - int num = colors.length; - alpha /= num; - red /= num; - green /= num; - blue /= num; - return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0); - } - - /** - * Assumes the top layer is a transparent color and the bottom is opaque - */ - public int combineTransparency(int top, int bottom) { - int alpha1 = (top >> 24) & 0xFF; - int alpha2 = 255 - alpha1; - int red1 = (top >> 16) & 0xFF; - int green1 = (top >> 8) & 0xFF; - int blue1 = (top >> 0) & 0xFF; - int red2 = (bottom >> 16) & 0xFF; - int green2 = (bottom >> 8) & 0xFF; - int blue2 = (bottom >> 0) & 0xFF; - int red = ((red1 * alpha1) + (red2 * alpha2)) / 255; - int green = ((green1 * alpha1) + (green2 * alpha2)) / 255; - int blue = ((blue1 * alpha1) + (blue2 * alpha2)) / 255; - return (red << 16) + (green << 8) + (blue << 0) + (255 << 24); - } - protected void calculateLayerArrays() { Int2ObjectOpenHashMap colorLayerMap = new Int2ObjectOpenHashMap<>(); for (int i = 0; i < validBlockIds.length; i++) { @@ -928,7 +1030,7 @@ public class TextureUtil implements TextureHolder { if (!hasAlpha(colorOther)) { int combinedOther = validBlockIds[j]; int combinedColor = combineTransparency(color, colorOther); - colorLayerMap.put(combinedColor, new int[] {combined, combinedOther}); + colorLayerMap.put(combinedColor, new int[]{combined, combinedOther}); } } } @@ -956,7 +1058,7 @@ public class TextureUtil implements TextureHolder { int closest = 0; int red1 = (color >> 16) & 0xFF; int green1 = (color >> 8) & 0xFF; - int blue1 = (color >> 0) & 0xFF; + int blue1 = (color) & 0xFF; int alpha = (color >> 24) & 0xFF; int intensity1 = 2 * red1 + 4 * green1 + 3 * blue1; for (int i = 0; i < validColors.length; i++) { @@ -964,7 +1066,7 @@ public class TextureUtil implements TextureHolder { if (other != color && ((other >> 24) & 0xFF) == alpha) { int red2 = (other >> 16) & 0xFF; int green2 = (other >> 8) & 0xFF; - int blue2 = (other >> 0) & 0xFF; + int blue2 = (other) & 0xFF; int intensity2 = 2 * red2 + 4 * green2 + 3 * blue2; if (darker ? intensity2 >= intensity1 : intensity1 >= intensity2) { continue; @@ -1003,36 +1105,6 @@ public class TextureUtil implements TextureHolder { return alpha != 255; } - protected long colorDistance(int red1, int green1, int blue1, int c2) { - int red2 = (c2 >> 16) & 0xFF; - int green2 = (c2 >> 8) & 0xFF; - int blue2 = (c2 >> 0) & 0xFF; - int rmean = (red1 + red2) >> 1; - int r = red1 - red2; - int g = green1 - green2; - int b = blue1 - blue2; - int hd = hueDistance(red1, green1, blue1, red2, green2, blue2); - return (((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8) + (hd * hd); - } - - public long getDistance(BufferedImage image, int c1) { - long totalDistSqr = 0; - int width = image.getWidth(); - int height = image.getHeight(); - int area = width * height; - int red1 = (c1 >> 16) & 0xFF; - int green1 = (c1 >> 8) & 0xFF; - int blue1 = (c1 >> 0) & 0xFF; - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) { - int c2 = image.getRGB(x, y); - long distance = colorDistance(red1, green1, blue1, c2); - totalDistSqr += distance * distance; - } - } - return totalDistSqr / area; - } - public int[] getValidBlockIds() { return validBlockIds.clone(); } diff --git a/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java b/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java index 541a00852..7c50cd9cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java @@ -350,7 +350,7 @@ public final class StringUtil { */ public static List split(String input, char delimiter, char open, char close) { if (input.indexOf(open) == -1 && input.indexOf(close) == -1) { - return Arrays.asList(input.split(String.valueOf(delimiter))); + return Arrays.asList(input.split(String.valueOf(delimiter), -1)); } int level = 0; int begin = 0; @@ -366,7 +366,7 @@ public final class StringUtil { level--; } } - if (begin < input.length()) { + if (begin <= input.length()) { split.add(input.substring(begin)); } return split; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index 17438b82c..f97735dee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extent.ResettableExtent; import com.google.common.base.Throwables; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; @@ -37,6 +38,7 @@ import com.sk89q.worldedit.extension.factory.BlockFactory; import com.sk89q.worldedit.extension.factory.ItemFactory; import com.sk89q.worldedit.extension.factory.MaskFactory; import com.sk89q.worldedit.extension.factory.PatternFactory; +import com.fastasyncworldedit.core.extension.factory.TransformFactory; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; @@ -138,6 +140,7 @@ public final class WorldEdit { private final ItemFactory itemFactory = new ItemFactory(this); private final MaskFactory maskFactory = new MaskFactory(this); private final PatternFactory patternFactory = new PatternFactory(this); + private final TransformFactory transformFactory = new TransformFactory(this); static { getVersion(); @@ -240,6 +243,16 @@ public final class WorldEdit { return patternFactory; } + /** + * Get the transform factory from which new {@link ResettableExtent}s + * can be constructed. + * + * @return the transform factory + */ + public TransformFactory getTransformFactory() { + return transformFactory; + } + /** * Return the session manager. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 15a04d03c..0c7cea3ef 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -86,6 +86,18 @@ import static com.google.common.base.Preconditions.checkNotNull; @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class GeneralCommands { + private final WorldEdit worldEdit; + + /** + * Create a new instance. + * + * @param worldEdit reference to WorldEdit + */ + public GeneralCommands(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + } + public static void register( CommandRegistrationHandler registration, CommandManager commandManager, @@ -149,18 +161,6 @@ public class GeneralCommands { return CommandUtil.createNewCommandReplacementText("//perf " + flipped); } - private final WorldEdit worldEdit; - - /** - * Create a new instance. - * - * @param worldEdit reference to WorldEdit - */ - public GeneralCommands(WorldEdit worldEdit) { - checkNotNull(worldEdit); - this.worldEdit = worldEdit; - } - @Command( name = "/limit", desc = "Modify block change limit" @@ -451,50 +451,6 @@ public class GeneralCommands { ); } - private static class ItemSearcher implements Callable { - - private final boolean blocksOnly; - private final boolean itemsOnly; - private final String search; - private final int page; - - ItemSearcher(String search, boolean blocksOnly, boolean itemsOnly, int page) { - this.blocksOnly = blocksOnly; - this.itemsOnly = itemsOnly; - this.search = search; - this.page = page; - } - - @Override - public Component call() throws Exception { - String command = "/searchitem " + (blocksOnly ? "-b " : "") + (itemsOnly ? "-i " : "") + "-p %page% " + search; - Map results = new TreeMap<>(); - String idMatch = search.replace(' ', '_'); - String nameMatch = search.toLowerCase(Locale.ROOT); - for (ItemType searchType : ItemType.REGISTRY) { - if (blocksOnly && !searchType.hasBlockType()) { - continue; - } - - if (itemsOnly && searchType.hasBlockType()) { - continue; - } - final String id = searchType.getId(); - if (id.contains(idMatch)) { - Component name = searchType.getRichName(); - results.put(id, TextComponent.builder() - .append(name) - .append(" (" + id + ")") - .build()); - } - } - List list = new ArrayList<>(results.values()); - return PaginationBox.fromComponents("Search results for '" + search + "'", command, list) - .create(page); - } - - } - //FAWE start @Command( name = "/gtexture", @@ -592,15 +548,18 @@ public class GeneralCommands { } } - @Command( name = "/gtransform", aliases = {"gtransform"}, desc = "Set the global transform" ) @CommandPermissions({"worldedit.global-transform", "worldedit.transform.global"}) - public void gtransform(Player player, EditSession editSession, LocalSession session, ResettableExtent transform) throws - WorldEditException { + public void gtransform( + Player player, + EditSession editSession, + LocalSession session, + @Arg(desc = "The transform to set", def = "") ResettableExtent transform + ) throws WorldEditException { session.setTransform(transform); if (transform == null) { player.print(Caption.of("fawe.worldedit.general.transform.disabled")); @@ -648,5 +607,49 @@ public class GeneralCommands { actor.print(Caption.of("worldedit.fast.enabled")); } } + + private static class ItemSearcher implements Callable { + + private final boolean blocksOnly; + private final boolean itemsOnly; + private final String search; + private final int page; + + ItemSearcher(String search, boolean blocksOnly, boolean itemsOnly, int page) { + this.blocksOnly = blocksOnly; + this.itemsOnly = itemsOnly; + this.search = search; + this.page = page; + } + + @Override + public Component call() throws Exception { + String command = "/searchitem " + (blocksOnly ? "-b " : "") + (itemsOnly ? "-i " : "") + "-p %page% " + search; + Map results = new TreeMap<>(); + String idMatch = search.replace(' ', '_'); + String nameMatch = search.toLowerCase(Locale.ROOT); + for (ItemType searchType : ItemType.REGISTRY) { + if (blocksOnly && !searchType.hasBlockType()) { + continue; + } + + if (itemsOnly && searchType.hasBlockType()) { + continue; + } + final String id = searchType.getId(); + if (id.contains(idMatch)) { + Component name = searchType.getRichName(); + results.put(id, TextComponent.builder() + .append(name) + .append(" (" + id + ")") + .build()); + } + } + List list = new ArrayList<>(results.values()); + return PaginationBox.fromComponents("Search results for '" + search + "'", command, list) + .create(page); + } + + } //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java index 1f18db58d..12edce796 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java @@ -23,6 +23,7 @@ import com.fastasyncworldedit.core.command.tool.TargetMode; import com.fastasyncworldedit.core.command.tool.brush.BrushSettings; import com.fastasyncworldedit.core.command.tool.scroll.Scroll; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extent.ResettableExtent; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.StringMan; import com.google.common.collect.Iterables; @@ -360,33 +361,33 @@ public class ToolUtilCommands { player.print(Caption.of("fawe.worldedit.brush.brush.source.mask")); } - // TODO: Ping @MattBDev to reimplement 2020-02-04 -// @Command( -// name = "transform", -// desc = "Set the brush transform" -// ) -// @CommandPermissions({"worldedit.brush.options.transform", "worldedit.transform.brush"}) -// public void transform(Player player, LocalSession session, EditSession editSession, -// @Arg(desc = "The transform", def = "") ResettableExtent transform, -// @Switch(name = 'h', desc = "Whether the offhand should be considered or not") -// boolean offHand, -// Arguments arguments) throws WorldEditException { -// BrushTool tool = session.getBrushTool(player, false); -// if (tool == null) { -// player.print(TranslatableComponent.of("fawe.worldedit.brush.brush.none")); -// return; -// } -// if (transform == null) { -// player.print(TranslatableComponent.of("fawe.worldedit.brush.brush.transform.disabled")); -// tool.setTransform(null); -// return; -// } -// BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext(); -// String lastArg = Iterables.getLast(CommandArgParser.spaceSplit(arguments.get())).getSubstring(); -// settings.addSetting(BrushSettings.SettingType.TRANSFORM, lastArg); -// settings.setTransform(transform); -// tool.update(); -// player.print(TranslatableComponent.of("fawe.worldedit.brush.brush.transform")); -// } + @Command( + name = "transform", + aliases = {"/transform"}, + desc = "Set the brush transform" + ) + @CommandPermissions({"worldedit.brush.options.transform", "worldedit.transform.brush"}) + public void transform(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The transform", def = "") ResettableExtent transform, + @Switch(name = 'h', desc = "Whether the offhand should be considered or not") + boolean offHand, + Arguments arguments) throws WorldEditException { + BrushTool tool = session.getBrushTool(player, false); + if (tool == null) { + player.print(Caption.of("fawe.worldedit.brush.brush.none")); + return; + } + if (transform == null) { + player.print(Caption.of("fawe.worldedit.brush.brush.transform.disabled")); + tool.setTransform(null); + return; + } + BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext(); + String lastArg = Iterables.getLast(CommandArgParser.spaceSplit(arguments.get())).getSubstring(); + settings.addSetting(BrushSettings.SettingType.TRANSFORM, lastArg); + settings.setTransform(transform); + tool.update(); + player.print(Caption.of("fawe.worldedit.brush.brush.transform")); + } //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index 88a7b07df..a52ed9201 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.command.argument; +import com.fastasyncworldedit.core.extent.ResettableExtent; import com.fastasyncworldedit.core.extent.SupplyingExtent; import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.LocalSession; @@ -54,6 +55,23 @@ import java.util.function.Function; public class FactoryConverter implements ArgumentConverter { + private final WorldEdit worldEdit; + private final Function> factoryExtractor; + private final String description; + @Nullable + private final Consumer contextTweaker; + private FactoryConverter( + WorldEdit worldEdit, + Function> factoryExtractor, + String description, + @Nullable Consumer contextTweaker + ) { + this.worldEdit = worldEdit; + this.factoryExtractor = factoryExtractor; + this.description = description; + this.contextTweaker = contextTweaker; + } + public static void register(WorldEdit worldEdit, CommandManager commandManager) { commandManager.registerConverter( Key.of(Pattern.class), @@ -67,6 +85,10 @@ public class FactoryConverter implements ArgumentConverter { Key.of(BaseItem.class), new FactoryConverter<>(worldEdit, WorldEdit::getItemFactory, "item", null) ); + commandManager.registerConverter( + Key.of(ResettableExtent.class), + new FactoryConverter<>(worldEdit, WorldEdit::getTransformFactory, "transform", null) + ); commandManager.registerConverter( Key.of(Mask.class, ClipboardMask.class), @@ -90,24 +112,6 @@ public class FactoryConverter implements ArgumentConverter { ); } - private final WorldEdit worldEdit; - private final Function> factoryExtractor; - private final String description; - @Nullable - private final Consumer contextTweaker; - - private FactoryConverter( - WorldEdit worldEdit, - Function> factoryExtractor, - String description, - @Nullable Consumer contextTweaker - ) { - this.worldEdit = worldEdit; - this.factoryExtractor = factoryExtractor; - this.description = description; - this.contextTweaker = contextTweaker; - } - @Override public ConversionResult convert(String argument, InjectedValueAccess context) { Actor actor = context.injectedValue(Key.of(Actor.class)) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java index 102685dda..899fd07a0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java @@ -234,6 +234,27 @@ public final class SuggestionHelper { return Stream.empty(); } + //FAWE start + /** + * Returns a stream of suggestions for booleans. + * + * @param argumentInput the given input to filter with. + * @return a stream of suggestions. + */ + public static Stream suggestBoolean(String argumentInput) { + if (argumentInput.isEmpty()) { + return Stream.of("true", "false"); + } + if ("true".startsWith(argumentInput)) { + return Stream.of("true"); + } else if ("false".startsWith(argumentInput)) { + return Stream.of("false"); + } + // no valid input anymore + return Stream.empty(); + } + //FAWE end + private static boolean isDouble(String input) { boolean point = false; for (char c : input.toCharArray()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java index 61f8c3015..388ea4d83 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.extension.factory; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extension.factory.parser.mask.AdjacentMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.mask.AngleMaskParser; +import com.fastasyncworldedit.core.extension.factory.parser.mask.RichMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.mask.ExtremaMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.mask.FalseMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.mask.LiquidMaskParser; @@ -71,6 +72,10 @@ import java.util.stream.Collectors; */ public final class MaskFactory extends AbstractFactory { + //FAWE start - rich mask parsing + private final RichMaskParser richMaskParser; + //FAWE end + /** * Create a new mask registry. * @@ -79,6 +84,10 @@ public final class MaskFactory extends AbstractFactory { public MaskFactory(WorldEdit worldEdit) { super(worldEdit, new BlocksMaskParser(worldEdit)); + //FAWE start - rich mask parsing + richMaskParser = new RichMaskParser(worldEdit); + //FAWE end + register(new ExistingMaskParser(worldEdit)); register(new AirMaskParser(worldEdit)); register(new SolidMaskParser(worldEdit)); @@ -133,20 +142,63 @@ public final class MaskFactory extends AbstractFactory { continue; } - Mask match = null; - for (InputParser parser : getParsers()) { - match = parser.parseFromInput(component, context); - - if (match != null) { - break; - } + //FAWE start - rich mask parsing + Mask match = richMaskParser.parseFromInput(component, context); + if (match != null) { + masks.add(match); + continue; } - if (match == null) { - throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); - } - masks.add(match); + parseFromParsers(context, masks, component); + //FAWE end } + return getMask(input, masks); + } + + //FAWE start - rich mask parsing + private void parseFromParsers( + final ParserContext context, + final List masks, + final String component + ) { + Mask match = null; + for (InputParser parser : getParsers()) { + match = parser.parseFromInput(component, context); + + if (match != null) { + break; + } + } + if (match == null) { + throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); + } + masks.add(match); + } + + /** + * Parses a mask without considering parsing through the {@link RichMaskParser}, therefore not accepting + * "richer" parsing where & and , are used. Exists to prevent stack overflows. + * + * @param input input string + * @param context input context + * @return parsed result + * @throws InputParseException if no result found + */ + public Mask parseWithoutRich(String input, ParserContext context) throws InputParseException { + List masks = new ArrayList<>(); + + for (String component : input.split(" ")) { + if (component.isEmpty()) { + continue; + } + + parseFromParsers(context, masks, component); + } + + return getMask(input, masks); + } + + private Mask getMask(final String input, final List masks) { switch (masks.size()) { case 0: throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); @@ -156,5 +208,6 @@ public final class MaskFactory extends AbstractFactory { return new MaskIntersection(masks).optimize(); } } + //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java index b85f4c0af..0b383ba39 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java @@ -19,24 +19,56 @@ package com.sk89q.worldedit.extension.factory; +import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.AngleColorPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.AverageColorPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.BiomePatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.BufferedPattern2DParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.BufferedPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.ColorPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.DarkenPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.DesaturatePatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.ExistingPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.ExpressionPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.LightenPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.Linear2DPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.Linear3DPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.LinearPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.MaskedPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.NoXPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.NoYPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.NoZPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.OffsetPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.PerlinPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.RandomFullClipboardPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.RandomOffsetPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RandomPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.RelativePatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.RichPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RidgedMultiFractalPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.SaturatePatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.SimplexPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.SolidRandomOffsetPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.SurfaceRandomOffsetPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.VoronoiPatternParser; +import com.fastasyncworldedit.core.math.random.TrueRandom; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.factory.parser.pattern.BlockCategoryPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.ClipboardPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.internal.registry.AbstractFactory; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +import java.util.ArrayList; +import java.util.List; /** * A registry of known {@link Pattern}s. Provides methods to instantiate @@ -47,6 +79,10 @@ import com.sk89q.worldedit.internal.registry.AbstractFactory; */ public final class PatternFactory extends AbstractFactory { + //FAWE start - rich pattern parsing + private final RichPatternParser richPatternParser; + //FAWE end + /** * Create a new instance. * @@ -55,6 +91,10 @@ public final class PatternFactory extends AbstractFactory { public PatternFactory(WorldEdit worldEdit) { super(worldEdit, new SingleBlockPatternParser(worldEdit)); + //FAWE start - rich pattern parsing + richPatternParser = new RichPatternParser(worldEdit); + //FAWE end + // split and parse each sub-pattern register(new RandomPatternParser(worldEdit)); @@ -65,16 +105,117 @@ public final class PatternFactory extends AbstractFactory { register(new BlockCategoryPatternParser(worldEdit)); //FAWE start - register(new SimplexPatternParser(worldEdit)); - register(new VoronoiPatternParser(worldEdit)); - register(new PerlinPatternParser(worldEdit)); - register(new RidgedMultiFractalPatternParser(worldEdit)); + register(new AngleColorPatternParser(worldEdit)); + register(new AverageColorPatternParser(worldEdit)); register(new BiomePatternParser(worldEdit)); + register(new BufferedPatternParser(worldEdit)); + register(new BufferedPattern2DParser(worldEdit)); + register(new ColorPatternParser(worldEdit)); + register(new DarkenPatternParser(worldEdit)); + register(new DesaturatePatternParser(worldEdit)); + register(new ExistingPatternParser(worldEdit)); + register(new ExpressionPatternParser(worldEdit)); + register(new LightenPatternParser(worldEdit)); register(new Linear2DPatternParser(worldEdit)); register(new Linear3DPatternParser(worldEdit)); - register(new BufferedPatternParser(worldEdit)); - register(new ExistingPatternParser(worldEdit)); + register(new LinearPatternParser(worldEdit)); + register(new MaskedPatternParser(worldEdit)); + register(new NoXPatternParser(worldEdit)); + register(new NoYPatternParser(worldEdit)); + register(new NoZPatternParser(worldEdit)); + register(new OffsetPatternParser(worldEdit)); + register(new PerlinPatternParser(worldEdit)); + register(new RandomFullClipboardPatternParser(worldEdit)); + register(new RandomOffsetPatternParser(worldEdit)); + register(new RelativePatternParser(worldEdit)); + register(new RidgedMultiFractalPatternParser(worldEdit)); + register(new SaturatePatternParser(worldEdit)); + register(new SimplexPatternParser(worldEdit)); + register(new SolidRandomOffsetPatternParser(worldEdit)); + register(new SurfaceRandomOffsetPatternParser(worldEdit)); + register(new VoronoiPatternParser(worldEdit)); //FAWE end } + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + List patterns = new ArrayList<>(); + + for (String component : input.split(" ")) { + if (component.isEmpty()) { + continue; + } + + //FAWE start - rich pattern parsing + Pattern match = richPatternParser.parseFromInput(component, context); + if (match != null) { + patterns.add(match); + continue; + } + parseFromParsers(context, patterns, component); + //FAWE end + } + + return getPattern(input, patterns); + } + + //FAWE start - rich pattern parsing + private void parseFromParsers( + final ParserContext context, + final List patterns, + final String component + ) { + Pattern match = null; + for (InputParser parser : getParsers()) { + match = parser.parseFromInput(component, context); + + if (match != null) { + break; + } + } + if (match == null) { + throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); + } + patterns.add(match); + } + + /** + * Parses a pattern without considering parsing through the {@link RichPatternParser}, therefore not accepting + * "richer" parsing where & and , are used. Exists to prevent stack overflows. + * + * @param input input string + * @param context input context + * @return parsed result + * @throws InputParseException if no result found + */ + public Pattern parseWithoutRich(String input, ParserContext context) throws InputParseException { + List patterns = new ArrayList<>(); + + for (String component : input.split(" ")) { + if (component.isEmpty()) { + continue; + } + + parseFromParsers(context, patterns, component); + } + + return getPattern(input, patterns); + } + + private Pattern getPattern(final String input, final List patterns) { + switch (patterns.size()) { + case 0: + throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); + case 1: + return patterns.get(0); + default: + RandomPattern randomPattern = new RandomPattern(new TrueRandom()); + for (Pattern pattern : patterns) { + randomPattern.add(pattern, 1d); + } + return randomPattern; + } + } + //FAWE end + } 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 b72c9aaf4..77cac97bc 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 @@ -354,6 +354,7 @@ public class DefaultBlockParser extends InputParser { throw new InputParseException(Caption.of("worldedit.error.incomplete-region")); } state = world.getBlock(primaryPosition); + nbt = state.getNbtData(); //FAWE start } else if (typeString.matches("slot[0-9]+")) { int slot = Integer.parseInt(typeString.substring(4)) - 1; @@ -384,9 +385,6 @@ public class DefaultBlockParser extends InputParser { throw new NoMatchException(Caption.of("fawe.error.invalid-block-type", TextComponent.of(input))); } } - if (nbt == null) { - nbt = state.getNbtData(); - } //FAWE end blockStates.putAll(parseProperties(state.getBlockType(), stateProperties, context)); @@ -477,7 +475,17 @@ public class DefaultBlockParser extends InputParser { return validate(context, new SkullBlock(state, type.replace(" ", "_"))); // valid MC usernames } else { - return validate(context, state.toBaseBlock()); + //FAWE start + nbt = state.getNbtData(); + BaseBlock result; + if (nbt != null) { + WorldEdit.logger.info(blockStates.size()); + result = blockStates.size() > 0 ? state.toBaseBlock(nbt) : new BlanketBaseBlock(state, nbt); + } else { + result = state.toBaseBlock(); + } + return validate(context, result); + //FAWE end } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java index 50f134156..36d83eb37 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extension.factory.parser.pattern; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extension.factory.parser.AliasedParser; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.extension.input.InputParseException; @@ -31,11 +32,15 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.block.BlockCategory; import com.sk89q.worldedit.world.block.BlockType; +import java.util.Collections; +import java.util.List; import java.util.Locale; import java.util.Set; import java.util.stream.Stream; -public class BlockCategoryPatternParser extends InputParser { +//FAWE start - aliased +public class BlockCategoryPatternParser extends InputParser implements AliasedParser { +//FAWE end public BlockCategoryPatternParser(WorldEdit worldEdit) { super(worldEdit); @@ -81,4 +86,11 @@ public class BlockCategoryPatternParser extends InputParser { return randomPattern; } + //FAWE start - aliased + @Override + public List getMatchedAliases() { + return Collections.singletonList("##"); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java index 5d7780781..f496c8c68 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.extension.factory.parser.pattern; +import com.fastasyncworldedit.core.extension.factory.parser.AliasedParser; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; @@ -28,9 +29,13 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.FuzzyBlockState; +import java.util.Collections; +import java.util.List; import java.util.stream.Stream; -public class RandomStatePatternParser extends InputParser { +//FAWE start - aliased +public class RandomStatePatternParser extends InputParser implements AliasedParser { +//FAWE end public RandomStatePatternParser(WorldEdit worldEdit) { super(worldEdit); @@ -68,4 +73,11 @@ public class RandomStatePatternParser extends InputParser { } } + //FAWE start - aliased + @Override + public List getMatchedAliases() { + return Collections.singletonList("*"); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java index bbf42f8a2..96f717d13 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extension.factory.parser.pattern; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extension.factory.parser.AliasedParser; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.extension.input.InputParseException; @@ -33,12 +34,15 @@ import com.sk89q.worldedit.function.pattern.TypeApplyingPattern; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.util.formatting.text.TextComponent; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.stream.Stream; - -public class TypeOrStateApplyingPatternParser extends InputParser { +//FAWE start - aliased +public class TypeOrStateApplyingPatternParser extends InputParser implements AliasedParser { +//FAWE end public TypeOrStateApplyingPatternParser(WorldEdit worldEdit) { super(worldEdit); @@ -128,4 +132,11 @@ public class TypeOrStateApplyingPatternParser extends InputParser { } } + //FAWE start - aliased + @Override + public List getMatchedAliases() { + return Collections.singletonList("^"); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 3ad589341..037c358e0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -839,8 +839,8 @@ public final class PlatformCommandManager { } //FAWE end - //FAWE start - Event & suggestions - private MemoizingValueAccess initializeInjectedValues(Arguments arguments, Actor actor, Event event, boolean isSuggestions) { + //FAWE start - Event & suggestions, make method public + public MemoizingValueAccess initializeInjectedValues(Arguments arguments, Actor actor, Event event, boolean isSuggestions) { //FAWE end InjectedValueStore store = MapBackedValueStore.create(); store.injectValue(Key.of(Actor.class), ValueProvider.constant(actor)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java index 15747a8a2..cb6ed7634 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -403,12 +403,34 @@ public interface Extent extends InputExtent, OutputExtent { } } + /** + * Returns true if the extent contains the given position + * + * @param pt position + * @return if position is contained + */ default boolean contains(BlockVector3 pt) { BlockVector3 min = getMinimumPoint(); BlockVector3 max = getMaximumPoint(); return pt.containedWithin(min, max); } + /** + * Returns true if the extent contains the given position + * + * @param x position x + * @param y position y + * @param z position z + * @return if position is contained + */ + default boolean contains(int x, int y, int z) { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + return min.getX() <= x && max.getX() >= x + && min.getY() <= y && max.getY() >= y + && min.getZ() <= z && max.getZ() >= z; + } + default void addOre( Region region, Mask mask, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index d544286f3..ef4299b33 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.internal.registry; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extension.factory.parser.AliasedParser; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; @@ -70,6 +71,17 @@ public abstract class AbstractFactory { return Collections.unmodifiableList(parsers); } + //FAWE start - javadoc + + /** + * Parse a string and context to each {@link InputParser} added to this factory. If no result found, throws {@link InputParseException} + * + * @param input input string + * @param context input context + * @return parsed result + * @throws InputParseException if no result found + */ + //FAWE end public E parseFromInput(String input, ParserContext context) throws InputParseException { E match; @@ -101,4 +113,19 @@ public abstract class AbstractFactory { parsers.add(parsers.size() - 1, inputParser); } + /** + * Test all parsers to see if alias is contained by one of them + * + * @param alias alias to test + * @return if a parser contains the alias + */ + public boolean containsAlias(String alias) { + return parsers.stream().anyMatch(p -> { + if (!(p instanceof AliasedParser)) { + return false; + } + return ((AliasedParser) p).getMatchedAliases().contains(alias); + }); + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java index c30ced38f..42ab41311 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java @@ -19,11 +19,11 @@ package com.sk89q.worldedit.internal.registry; +import com.fastasyncworldedit.core.extension.factory.parser.AliasedParser; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; -import java.util.List; import java.util.Locale; import java.util.stream.Stream; @@ -32,19 +32,14 @@ import java.util.stream.Stream; * * @param the element */ -public abstract class SimpleInputParser extends InputParser { +//FAWE start - AliasedParser interface, rather than method being here +public abstract class SimpleInputParser extends InputParser implements AliasedParser { +//FAWE end protected SimpleInputParser(WorldEdit worldEdit) { super(worldEdit); } - /** - * The strings this parser matches. - * - * @return the matching aliases - */ - public abstract List getMatchedAliases(); - @Override public E parseFromInput(String input, ParserContext context) throws InputParseException { if (!getMatchedAliases().contains(input)) { diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 886e2b70a..8c97636a3 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -60,6 +60,7 @@ "fawe.worldedit.brush.spline.secondary": "Created spline", "fawe.worldedit.brush.brush.source.mask.disabled": "Brush source mask disabled", "fawe.worldedit.brush.brush.source.mask": "Brush source mask set", + "fawe.worldedit.brush.brush.transform.disabled": "Brush transform disabled", "fawe.worldedit.brush.brush.transform": "Brush transform set", "fawe.worldedit.rollback.rollback.element": "Undoing {0}", @@ -135,6 +136,12 @@ "fawe.error.input-parser-exception": "Invalid empty string instead of boolean.", "fawe.error.invalid-boolean": "Invalid boolean {0}", "fawe.error.schematic.not.found": "Schematic {0} not found.", + "fawe.error.parse.invalid-dangling-character": "Invalid dangling character {0}.", + "fawe.error.parse.unknown-mask": "Unknown mask: {0}, See: {1}", + "fawe.error.parse.unknown-pattern": "Unknown pattern: {0}, See: {1}", + "fawe.error.parse.unknown-transform": "Unknown transform: {0}, See: {1}", + "fawe.error.parse.no-clipboard": "To use {0}, please first copy something to your clipboard", + "fawe.error.parse.no-clipboard-source": "No clipboards found at given source: {0}", "fawe.cancel.worldedit.cancel.count": "Cancelled {0} edits.", "fawe.cancel.worldedit.cancel.reason.confirm": "Use //confirm to execute {0}",