Add property pattern

This commit is contained in:
Jesse Boyd 2018-08-16 00:12:07 +10:00
parent f254027f4b
commit 7ed96ec358
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
3 changed files with 222 additions and 45 deletions

View File

@ -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<Property> 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<Property> 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<BlockTypes> 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;
}
}

View File

@ -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<? extends ZipEntry> 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) {

View File

@ -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 = "<file>",
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);
}
}