From 7ed96ec358622de10cb403e53037b1992b3c9b8d Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 16 Aug 2018 00:12:07 +1000 Subject: [PATCH] Add property pattern --- .../fawe/object/pattern/PropertyPattern.java | 219 ++++++++++++++++++ .../com/boydti/fawe/util/TextureUtil.java | 11 - .../worldedit/command/PatternCommands.java | 37 +-- 3 files changed, 222 insertions(+), 45 deletions(-) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java new file mode 100644 index 000000000..340e03532 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java @@ -0,0 +1,219 @@ +package com.boydti.fawe.object.pattern; + +import com.boydti.fawe.object.string.MutableCharSequence; +import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.StringMan; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.Extent; +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.registry.state.PropertyKey; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.ArrayList; +import java.util.List; + +public class PropertyPattern extends AbstractExtentPattern { + public PropertyPattern(Extent extent, String[] properties) { + super(extent); + addRegex(".*[" + StringMan.join(properties, ",") + "]"); + } + + public PropertyPattern(Extent extent) { + super(extent); + } + + private int[][] intSets = new int[BlockTypes.size()][]; + + 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(BlockTypes 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(); + + int[] states = null; + 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; + + if (states == null) { + states = intSets[type.getInternalId()]; + if (states == null) { + intSets[type.getInternalId()] = states = new int[type.getMaxStateId() + 1]; + for (int j = 0; j < states.length; j++) states[j] = j; + } + } + 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(property, properties, 0, state, result, states); + } else { + states[i] = result; + } + } + } + + private void applyRecursive(AbstractProperty property, List properties, int propertiesIndex, int state, int index, int[] states) { + 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(state, i); + applyRecursive(property, properties, propertiesIndex + 1, newState, index, states); + } + } else { + //set chest[waterlogged=north] + for (int i = 0; i < values.size(); i++) { + int statesIndex = current.modifyIndex(state, i) >> BlockTypes.BIT_OFFSET; + int existing = states[statesIndex] << BlockTypes.BIT_OFFSET; + states[statesIndex] = property.modifyIndex(existing, index) >> BlockTypes.BIT_OFFSET; + } + } + } + + 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); + + BlockTypes type = null; + List blockTypeList = null; + if (StringMan.isAlphanumericUnd(charSequence)) { + type = BlockTypes.get(charSequence); + } else { + String regex = charSequence.toString(); + blockTypeList = new ArrayList<>(); + for (BlockTypes myType : BlockTypes.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 (BlockTypes 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.get(charSequence); + last = i + 1; + } + break; + } + } + } + } + return this; + } + + @Override + public BlockStateHolder apply(Vector position) { + BlockState block = getExtent().getBlock(position); + return apply(block, block); + } + + public BlockState apply(BlockState block, BlockState orDefault) { + int typeId = block.getInternalBlockTypeId(); + int[] states = intSets[typeId]; + if (states == null) return orDefault; + int propertyId = block.getInternalPropertiesId(); + int newPropertyId = states[propertyId]; + if (newPropertyId == propertyId) return orDefault; + BlockState newState = block.withPropertyId(newPropertyId); + CompoundTag nbt = block.getNbtData(); + if (nbt == null) return newState; + return new BaseBlock(newState, nbt); + } + + @Override + public boolean apply(Extent extent, Vector set, Vector get) throws WorldEditException { + BlockState block = getExtent().getBlock(get); + block = apply(block, null); + if (block != null) { + return extent.setBlock(set, block); + } + return false; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java index 36f80aa9b..663d11bd6 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java @@ -535,17 +535,6 @@ public class TextureUtil implements TextureHolder{ return colorDistance(red1, green1, blue1, c2); } - public static void main(String[] args) throws IOException { - File tf = new File("1.13.jar"); - ZipFile zipFile = new ZipFile(tf); - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - System.out.println(entries.nextElement().getName()); - } -// TextureUtil tu = new TextureUtil(new File(".")); -// tu.loadModTextures(); - } - private BufferedImage readImage(ZipFile zipFile, String name) throws IOException { ZipEntry entry = getEntry(zipFile, name); if (entry != null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java index ed6ec1507..c2883fc5a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java @@ -1,8 +1,5 @@ package com.sk89q.worldedit.command; -import com.boydti.fawe.Fawe; -import com.boydti.fawe.FaweAPI; -import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.DataAnglePattern; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.clipboard.MultiClipboardHolder; @@ -11,12 +8,8 @@ import com.boydti.fawe.object.pattern.*; import com.boydti.fawe.object.random.SimplexRandom; import com.boydti.fawe.util.ColorUtil; import com.boydti.fawe.util.TextureUtil; -import com.boydti.fawe.wrappers.LocationMaskedPlayerWrapper; import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.platform.Actor; @@ -30,13 +23,11 @@ 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.regions.shape.WorldEditExpressionEnvironment; -import com.sk89q.worldedit.scripting.RhinoCraftScriptEngine; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.command.binding.Range; import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.world.biome.BaseBiome; import java.awt.Color; -import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.List; @@ -58,9 +49,9 @@ public class PatternCommands extends MethodCommands { @Command( aliases = {"#existing", "#*", "*", ".*"}, desc = "Use the block that is already there") - public Pattern existing(Extent extent) { // TODO FIXME , @Optional String properties - // TODO fixme apply properties - return new ExistingPattern(extent); + public Pattern existing(Extent extent, @Optional String properties) { // TODO FIXME , @Optional String properties + if (properties == null) return new ExistingPattern(extent); + return new PropertyPattern(extent).addRegex(".*[" + properties + "]"); } @Command( @@ -437,26 +428,4 @@ public class PatternCommands extends MethodCommands { exp.setEnvironment(env); return new ExpressionPattern(exp); } - - @Command( - aliases = {"cs", "craftscript"}, - desc = "CraftScript pattern", - usage = "", - min = 1, - max = 1 - ) - public Pattern expression(Player player, LocalSession session, final CommandContext args) throws WorldEditException { - final String[] scriptArgs = args.getSlice(1); - final String name = args.getString(0); - - if (!player.hasPermission("worldedit.scripting.execute." + name)) { - throw new InputParseException("You don't have permission to use that script."); - } - - File file = new File(Fawe.imp().getDirectory(), Settings.IMP.PATHS.PATTERNS + File.separator + name); - Player unwrapped = LocationMaskedPlayerWrapper.unwrap(player); - return ScriptingCommands.runScript(unwrapped, file, scriptArgs); - } - - }