Add support for data values in the blacklist.

This commit is contained in:
sk89q 2014-07-28 16:45:43 -07:00
parent 3aa8bbe947
commit 956d1b4248
12 changed files with 465 additions and 34 deletions

View File

@ -22,12 +22,13 @@
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.sk89q.worldedit.blocks.ItemType;
import com.sk89q.worldguard.blacklist.action.Action;
import com.sk89q.worldguard.blacklist.action.ActionType;
import com.sk89q.worldguard.blacklist.event.BlacklistEvent;
import com.sk89q.worldguard.blacklist.event.EventType;
import com.sk89q.worldguard.blacklist.target.WildcardDataMatcher;
import com.sk89q.worldguard.blacklist.target.TargetMatcher;
import com.sk89q.worldguard.blacklist.target.TargetMatcherParseException;
import com.sk89q.worldguard.blacklist.target.TargetMatcherParser;
import org.bukkit.ChatColor;
import java.io.BufferedReader;
@ -135,6 +136,7 @@ public boolean check(BlacklistEvent event, boolean forceRepeat, boolean silent)
public void load(File file) throws IOException {
FileReader input = null;
MatcherIndex.Builder builder = new MatcherIndex.Builder();
TargetMatcherParser targetMatcherParser = new TargetMatcherParser();
try {
input = new FileReader(file);
@ -157,29 +159,20 @@ public void load(File file) throws IOException {
currentEntries = new ArrayList<BlacklistEntry>();
for (String item : items) {
int id;
try {
id = Integer.parseInt(item.trim());
} catch (NumberFormatException e) {
id = getItemID(item.trim());
if (id == 0) {
logger.log(Level.WARNING, "Unknown block name: " + item);
break;
}
TargetMatcher matcher = targetMatcherParser.fromInput(item.trim());
BlacklistEntry entry = new BlacklistEntry(this);
builder.add(matcher, entry);
currentEntries.add(entry);
} catch (TargetMatcherParseException e) {
logger.log(Level.WARNING, "Could not parse a block/item heading: " + e.getMessage());
}
BlacklistEntry entry = new BlacklistEntry(this);
builder.add(new WildcardDataMatcher(id), entry);
currentEntries.add(entry);
}
} else if (currentEntries != null) {
String[] parts = line.split("=");
if (parts.length == 1) {
logger.log(Level.WARNING, "Found option with no value "
+ file.getName() + " for '" + line + "'");
logger.log(Level.WARNING, "Found option with no value " + file.getName() + " for '" + line + "'");
continue;
}
@ -293,21 +286,6 @@ public void notify(BlacklistEvent event, String comment) {
*/
public abstract void broadcastNotification(String msg);
/**
* Get an item's ID from its name.
*
* @param name the name of the item to look up
* @return the id for name if contained in ItemId, else -1
*/
private static int getItemID(String name) {
ItemType type = ItemType.lookup(name);
if (type != null) {
return type.getID();
} else {
return -1;
}
}
public Cache<String, TrackedEvent> getRepeatingEventCache() {
return repeatingEventCache;
}

View File

@ -43,7 +43,7 @@ private MatcherIndex(Table<Integer, TargetMatcher, BlacklistEntry> entries) {
public List<BlacklistEntry> getEntries(Target target) {
List<BlacklistEntry> found = new ArrayList<BlacklistEntry>();
for (Entry<TargetMatcher, BlacklistEntry> entry : entries.row(target.getTypeId()).entrySet()) {
if (entry.getKey().matches(target)) {
if (entry.getKey().test(target)) {
found.add(entry.getValue());
}
}

View File

@ -0,0 +1,28 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.blacklist.target;
import com.google.common.base.Predicate;
/**
* Tests a data value.
*/
public interface DataMask extends Predicate<Short> {
}

View File

@ -0,0 +1,51 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.blacklist.target;
import com.google.common.base.Predicate;
import static com.google.common.base.Preconditions.checkNotNull;
public class DataValueRangeMatcher implements TargetMatcher {
private final int typeId;
private final Predicate<Short> dataMatcher;
public DataValueRangeMatcher(int typeId, Predicate<Short> dataMatcher) {
checkNotNull(dataMatcher);
this.typeId = typeId;
this.dataMatcher = dataMatcher;
}
@Override
public int getMatchedTypeId() {
return typeId;
}
@Override
public boolean test(Target target) {
return typeId == target.getTypeId() && isDataInRange(target.getData());
}
private boolean isDataInRange(short data) {
return dataMatcher.apply(data);
}
}

View File

@ -0,0 +1,54 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.blacklist.target;
import com.sk89q.worldedit.blocks.ItemType;
public class MaterialTarget implements Target {
private int id;
private short data;
public MaterialTarget(int id, short data) {
this.id = id;
this.data = data;
}
@Override
public int getTypeId() {
return id;
}
@Override
public short getData() {
return data;
}
@Override
public String getFriendlyName() {
ItemType type = ItemType.fromID(id);
if (type != null) {
return type.getName() + " (#" + id + ":" + data + ")";
} else {
return "#" + id + ":" + data;
}
}
}

View File

@ -0,0 +1,40 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.blacklist.target;
import com.google.common.collect.Range;
import static com.google.common.base.Preconditions.checkNotNull;
public class RangeMask implements DataMask {
private final Range<Short> range;
public RangeMask(Range<Short> range) {
checkNotNull(range);
this.range = range;
}
@Override
public boolean apply(Short data) {
return range.contains(data);
}
}

View File

@ -0,0 +1,48 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.blacklist.target;
/**
* A target is something that can have events attached to it.
*/
public interface Target {
/**
* Get the type ID.
*
* @return the type ID
*/
int getTypeId();
/**
* Get the data value.
*
* @return the data value
*/
short getData();
/**
* Get a friendly name to be printed.
*
* @return a friendly name
*/
String getFriendlyName();
}

View File

@ -0,0 +1,42 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.blacklist.target;
/**
* Matches a {@link Target}.
*/
public interface TargetMatcher {
/**
* Get the matched type ID, which is merely used for indexing.
*
* @return the type ID
*/
int getMatchedTypeId();
/**
* Return whether the given target is matched by this matcher.
*
* @param target the target
* @return true if matched
*/
boolean test(Target target);
}

View File

@ -0,0 +1,30 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.blacklist.target;
import static com.google.common.base.Preconditions.checkNotNull;
public class TargetMatcherParseException extends Exception {
public TargetMatcherParseException(String message) {
super(checkNotNull(message));
}
}

View File

@ -0,0 +1,115 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.blacklist.target;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Ranges;
import com.sk89q.worldedit.blocks.ItemType;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TargetMatcherParser {
private static final Pattern DATA_VALUE_PATTERN = Pattern.compile("^([^:]+):([^:]+)$");
private static final Pattern LESS_THAN_PATTERN = Pattern.compile("^<=\\s*([0-9]+)$");
private static final Pattern GREATER_THAN_PATTERN = Pattern.compile("^>=\\s*([0-9]+)$");
private static final Pattern RANGE_PATTERN = Pattern.compile("^([0-9]+)\\s*-\\s*([0-9]+)$");
public TargetMatcher fromInput(String input) throws TargetMatcherParseException {
Matcher matcher = DATA_VALUE_PATTERN.matcher(input.trim());
if (matcher.matches()) {
return new DataValueRangeMatcher(parseType(matcher.group(1)), parseDataValueRanges(matcher.group(2)));
} else {
return new WildcardDataMatcher(parseType(input));
}
}
private int parseType(String input) throws TargetMatcherParseException {
input = input.trim();
try {
return Integer.parseInt(input);
} catch (NumberFormatException e) {
int id = getItemID(input);
if (id == 0) {
throw new TargetMatcherParseException("Unknown block or item name: " + input);
}
return id;
}
}
private Predicate<Short> parseDataValueRanges(String input) throws TargetMatcherParseException {
List<Predicate<Short>> predicates = new ArrayList<Predicate<Short>>();
for (String part : input.split(";")) {
predicates.add(parseRange(part));
}
return Predicates.or(predicates);
}
private Predicate<Short> parseRange(String input) throws TargetMatcherParseException {
input = input.trim();
Matcher matcher;
matcher = LESS_THAN_PATTERN.matcher(input);
if (matcher.matches()) {
return Ranges.atMost(Short.parseShort(matcher.group(1)));
}
matcher = GREATER_THAN_PATTERN.matcher(input);
if (matcher.matches()) {
return Ranges.atLeast(Short.parseShort(matcher.group(1)));
}
matcher = RANGE_PATTERN.matcher(input);
if (matcher.matches()) {
return Ranges.closed(Short.parseShort(matcher.group(1)), Short.parseShort(matcher.group(2)));
}
try {
short s = Short.parseShort(input);
return Ranges.closed(s, s);
} catch (NumberFormatException e) {
throw new TargetMatcherParseException("Unknown data value range: " + input);
}
}
/**
* Get an item's ID from its name.
*
* @param name the name of the item to look up
* @return the id for name if contained in ItemId, else -1
*/
private static int getItemID(String name) {
ItemType type = ItemType.lookup(name);
if (type != null) {
return type.getID();
} else {
return -1;
}
}
}

View File

@ -0,0 +1,40 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.blacklist.target;
public class WildcardDataMatcher implements TargetMatcher {
private final int typeId;
public WildcardDataMatcher(int typeId) {
this.typeId = typeId;
}
@Override
public int getMatchedTypeId() {
return typeId;
}
@Override
public boolean test(Target target) {
return target.getTypeId() == typeId;
}
}

View File

@ -57,4 +57,9 @@
# Deny some ore
#[coalore,goldore,ironore]
#ignore-groups=admins,mods
#on-break=notify,deny,log
# Some funky data value tests
#[wood:0;>=2]
#ignore-groups=admins,mods
#on-break=notify,deny,log