290 lines
8.8 KiB
Java
290 lines
8.8 KiB
Java
// $Id$
|
|
/*
|
|
* This file is a part of WorldGuard.
|
|
* Copyright (c) sk89q <http://www.sk89q.com>
|
|
* Copyright (c) the 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
|
|
* (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.region;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
|
|
import org.apache.commons.lang.Validate;
|
|
|
|
import com.sk89q.worldguard.region.attribute.Attribute;
|
|
import com.sk89q.worldguard.region.shapes.IndexableShape;
|
|
|
|
/**
|
|
* A region that has an ID, shape, priority, parent, and attributes assigned to
|
|
* it. It is used for defining areas on a world.
|
|
* <p>
|
|
* The casing of region IDs are maintained, but they are case insensitive for
|
|
* the purposes of indexing.
|
|
* <p>
|
|
* If changes are made to this region, and it is contained within a region
|
|
* index, the index must be notified of the change.
|
|
*/
|
|
public class Region implements Comparable<Region> {
|
|
|
|
private final String id;
|
|
private IndexableShape shape;
|
|
private int priority = 0;
|
|
private Region parent;
|
|
private Map<String, Attribute> attributes = new HashMap<String, Attribute>();
|
|
|
|
/**
|
|
* Construct a new instance of this region.
|
|
*
|
|
* @param id the ID of the region
|
|
* @param shape the shape of the region
|
|
*/
|
|
public Region(String id, IndexableShape shape) {
|
|
Validate.notNull(id, "Region ID cannot be null");
|
|
Validate.notNull(shape, "Shape parameter cannot be null");
|
|
|
|
this.id = id;
|
|
this.shape = shape;
|
|
}
|
|
|
|
/**
|
|
* Gets the ID of this region. IDs maintain casing but are case insensitive
|
|
* during comparison.
|
|
*
|
|
* @return the id
|
|
*/
|
|
public String getId() {
|
|
return id;
|
|
}
|
|
|
|
/**
|
|
* Get the shape defining this region.
|
|
*
|
|
* @return a shape
|
|
*/
|
|
public IndexableShape getShape() {
|
|
return shape;
|
|
}
|
|
|
|
/**
|
|
* Set a shape defining this region.
|
|
*
|
|
* @param shape a shape
|
|
*/
|
|
public void setShape(IndexableShape shape) {
|
|
Validate.notNull(shape, "Shape parameter cannot be null");
|
|
this.shape = shape;
|
|
}
|
|
|
|
/**
|
|
* Get the priority of the region. Priorities determine the resolution order of
|
|
* flags, where greater numbers indicate higher precedence. The default priority
|
|
* of a newly created region is 0, and negative priorities are also supported.
|
|
*
|
|
* @return the priority
|
|
*/
|
|
public int getPriority() {
|
|
return priority;
|
|
}
|
|
|
|
/**
|
|
* Set the priority of the region.
|
|
*
|
|
* @see #getPriority() for an explanation of priorities
|
|
* @param priority the priority
|
|
*/
|
|
public void setPriority(int priority) {
|
|
this.priority = priority;
|
|
}
|
|
|
|
/**
|
|
* Get the parent of the region. Parents can determine how multiple overlapping
|
|
* regions are handled in regards to some flags, but it is dependent on the flag.
|
|
*
|
|
* @return parent region or null
|
|
*/
|
|
public Region getParent() {
|
|
return parent;
|
|
}
|
|
|
|
/**
|
|
* Set the parent of this region.
|
|
*
|
|
* @see #getParent() for an explanation of parents
|
|
* @param parent the new parent, or null
|
|
* @throws IllegalArgumentException when circular inheritance is detected
|
|
*/
|
|
public synchronized void setParent(Region parent) throws IllegalArgumentException {
|
|
if (parent == null) {
|
|
this.parent = null;
|
|
} else {
|
|
if (parent == this) {
|
|
throw new IllegalArgumentException(
|
|
"Circular region inheritance detected");
|
|
}
|
|
|
|
Region p = parent.getParent();
|
|
while (p != null) {
|
|
if (p == this) {
|
|
throw new IllegalArgumentException(
|
|
"Circular region inheritance detected");
|
|
}
|
|
|
|
p = p.getParent();
|
|
}
|
|
|
|
this.parent = parent;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set an attribute to this region.
|
|
* <p>
|
|
* While more than one region can share an attribute object, this is not
|
|
* recommended. On region index save and then load, the attribute would
|
|
* be re-created individually for each region.
|
|
* <p>
|
|
* If an attribute of the same name already exists on this region, the
|
|
* existing attribute will be replaced with the given one. Attribute
|
|
* names are case-sensitive.
|
|
* <p>
|
|
* This method is thread-safe.
|
|
*
|
|
* @param attribute the attribute
|
|
*/
|
|
public synchronized void set(Attribute attribute) {
|
|
attributes.put(attribute.getName(), attribute);
|
|
}
|
|
|
|
/**
|
|
* Remove an attribute with the same name from this region.
|
|
* <p>
|
|
* Attribute names are case-sensitive. This method is thread-safe.
|
|
*
|
|
* @param attribute the attribute
|
|
*/
|
|
public synchronized void remove(Attribute attribute) {
|
|
attributes.remove(attribute.getName());
|
|
}
|
|
|
|
/**
|
|
* Returns whether this region contains this attribute.
|
|
* <p>
|
|
* Recall that {@link Attribute#equals(Object)} is true if two attributes
|
|
* have the same name, and so this merely checks whether an attribute
|
|
* of the same name exists on this region. Attribute names are
|
|
* case-sensitive.
|
|
* <p>
|
|
* This method is thread-safe.
|
|
*
|
|
* @param attribute the attribute
|
|
* @return true if this region contains the attribute
|
|
*/
|
|
public synchronized boolean contains(Attribute attribute) {
|
|
return attributes.containsKey(attribute.getName());
|
|
}
|
|
|
|
/**
|
|
* Get the actual stored attribute on this region based on the attribute
|
|
* type given as a parameter.
|
|
* <p>
|
|
* The returned object may or may not be the same as the given object,
|
|
* but the returned attribute will definitely have the same name. Attribute
|
|
* names are case-sensitive.
|
|
* <p>
|
|
* At the moment, if the attribute stored on this region is of a different
|
|
* type than the given attribute, that is an undefined situation and
|
|
* bad things will occur.
|
|
*
|
|
* @param attribute attribute to get
|
|
* @return the attribute stored on this region or null otherwise
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public synchronized <E extends Attribute> E get(E attribute) {
|
|
return (E) attributes.get(attribute.getName());
|
|
}
|
|
|
|
/**
|
|
* Rename the given attribute to a new name, and add the attribute to
|
|
* this region if doesn't already exist on this region.
|
|
* <p>
|
|
* This is the only safe way to rename an attribute, assuming that the
|
|
* given attribute is not being used across several regions
|
|
* (not good!). Attribute names are also case-sensitive. Attempting
|
|
* to rename an attribute to the same name does nothing.
|
|
* <p>
|
|
* While this method is thread safe, the given attribute must not change
|
|
* in another thread in the process of the rename operation.
|
|
*
|
|
* @param attribute attribute to rename
|
|
* @param newName new attribute name to use
|
|
*/
|
|
public synchronized void rename(Attribute attribute, String newName) {
|
|
if (attribute.getName().equals(newName)) return;
|
|
|
|
remove(attribute);
|
|
attribute.setName(newName);
|
|
set(attribute);
|
|
}
|
|
|
|
/**
|
|
* Compares to another region.
|
|
* <ul>
|
|
* <li>Orders primarily by the priority, descending</li>
|
|
* <li>Orders secondarily by the id, ascending</li>
|
|
* </ul>
|
|
*
|
|
* @param other the region to compare to
|
|
*/
|
|
@Override
|
|
public int compareTo(Region other) {
|
|
if (priority > other.priority) {
|
|
return -1;
|
|
} else if (priority < other.priority) {
|
|
return 1;
|
|
}
|
|
|
|
return id.compareTo(other.id);
|
|
}
|
|
|
|
/**
|
|
* Returns whether this is a high frequency region that should be placed in a
|
|
* faster index for frequent access. Indices may or may not adhere to the
|
|
* return value of this method.
|
|
*
|
|
* @return true if this is a high frequency region.
|
|
*/
|
|
public boolean shouldCache() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns whether this region has the same ID as another region.
|
|
*/
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (!(obj instanceof Region)) {
|
|
return false;
|
|
}
|
|
|
|
Region other = (Region) obj;
|
|
return other.getId().equals(getId());
|
|
}
|
|
|
|
@Override
|
|
public int hashCode(){
|
|
return id.hashCode();
|
|
}
|
|
}
|