Regions

Every region object is a subclass of the ProtectedRegion class, and there are several subclasses:

  • ProtectedCuboidRegion
  • ProtectedPolygonalRegion
  • GlobalProtectedRegion

Each region object stores:

  • An ID (immutable)
  • Its priority
  • Its (optional) parent
  • A list of members
  • A list of owners
  • A list of region flags
  • A boolean that automatically tracks whether the region has been modified

Vectors are used for referring to locations — these vector objects are from WorldEdit (see From Bukkit Objects for converting from Bukkit locations).

Example: Changing the priority of a region

region.setPriority(100);

Example: Setting the parent of a region

mall.setParent(null); // No parent
plot.setParent(mall);

If you attempt to create a scenario where there is circular inheritance, an exception will be thrown.

Example: Getting polygon vertices out of a region

if (region instanceof ProtectedPolygonalRegion) {
    ProtectedPolygonalRegion polygon = (ProtectedPolygonalRegion) region;
    List<BlockVector2D> points = polygon.getPoints();
}

Domains

Owners and members (region.getOwners() and region.getMembers()) are separate instances of DefaultDomain, which holds player names, player UUIDs, and permission groups.

Example: Adding members to a region

DefaultDomain members = region.getMembers();
members.addPlayer(UUID.fromString("0ea8eca3-dbf6-47cc-9d1a-c64551ca975c"));
members.addGroup("admins");

Warning

Referring to players by name (instead of by UUID) should generally not be done as names can be changed. Offline mode is not explicitly supported and those who use it do so at their own risk. Methods in Domains that use names instead of UUIDs are marked deprecated.

Example: Converting names to UUIDs in the background

If you need to convert player names into UUIDs, you should try to do it in the background if possible so that you do not pause the server or game.

You can use WorldGuard’s DomainInputResolver class to help you do that. It implements Callable<DefaultDomain> and will return a DefaultDomain object that can be added to an existing domain. It takes input in the format of the member management commands. This is illustrated below.

// Google's Guava library provides useful concurrency classes.
// The following executor would be re-used in your plugin.
ListeningExecutorService executor =
        MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());

String[] input = new String[] { "sk89q", "g:admins" };
ProfileService profiles = WorldGuard.getInstance().getProfileService();
DomainInputResolver resolver = new DomainInputResolver(profiles, input);
resolver.setLocatorPolicy(UserLocatorPolicy.UUID_AND_NAME);
ListenableFuture<DefaultDomain> future = executor.submit(resolver);

// Add a callback using Guava
Futures.addCallback(future, new FutureCallback<DefaultDomain>() {
    @Override
    public void onSuccess(DefaultDomain result) {
        region.getOwners().addAll(result);
    }

    @Override
    public void onFailure(Throwable throwable) {
        // Do something about the error
    }
});

It is highly recommended that you inform the user if the UUID lookup does not complete instantly.

Flags

Flags can be read by calling getFlag(Flag flag). You can find static Flag objects on Flags:

Flags.BUILD
Flags.PVP
Flags.LEAF_DECAY
Flags.LIGHTNING

The returned value will be of the data type of the flag. For example, if you were to use Flags.GREET_MESSAGE, which is a StringFlag, a String will be returned.

Example: Getting the greeting message

String message = region.getFlag(Flags.GREET_MESSAGE);
player.sendMessage(message);

If the given flag is not set, null will be returned.

Setting Flags

Flags can be set using setFlag(Flag flag, ? value). The value that you use must be of the type that the flag allows. For example, if the flag is a StringFlag, you can only set a String:

region.setFlag(Flags.GREET_MESSAGE, "Hi there!");

Flags can be removed by using null for the value.

Region groups can be set by calling getRegionGroupFlag() on a flag to get its region group flag:

RegionGroupFlag flag = Flags.PVP.getRegionGroupFlag();

Example: Setting the region group of the use flag:

region.setFlag(Flags.USE, StateFlag.State.ALLOW);
region.setFlag(Flags.USE.getRegionGroupFlag(), RegionGroup.MEMBERS);

Custom Flags

As of version 6.2, plugins can add their own flags and session handlers. See the Custom Flags and Session Handlers page.

Creating Regions

ProtectedRegion is an abstract class, so you must use one of the subclasses. For example, you might use a ProtectedCuboidRegion.

In every case, a region ID must be passed for the region. Valid regions must match the regular expression ^[A-Za-z0-9_,'\-\+/]{1,} — that is, region IDs are only valid if they contain A-Z, a-z, 0-9, underscores, commas, single quotation marks, dashes, pluses, or forward slashes. IDs are case in-sensitive. The validity of an ID can be verified using ProtectedRegion.isValidId(String).

To save a created region, see Managers.

Cuboids

To create a new cuboid region, two opposite corners are required. Any two opposite two corners are acceptable.

BlockVector3 min = BlockVector3.at(-10, 5, -4);
BlockVector3 max = BlockVector3.at(5, -8, 10);
ProtectedRegion region = new ProtectedCuboidRegion("spawn", min, max);

2D Polygon

Only 2D polygons are supported. These are polygons that have been extended vertically, which means that a minimum Y and a maximum Y are needed to create a 2D polygon region. A minimum of three points is required to create a valid 2D polygonal region.

List<BlockVector2> points = Lists.newArrayList(); // Call from Guava
points.add(BlockVector2.at(3, 4));
points.add(BlockVector2.at(0, 0));
points.add(BlockVector2.at(19, 3));
int minY = 0;
int maxY = 54;
ProtectedRegion region = new ProtectedPolygonalRegion("spawn", points, minY, maxY);

Global Regions

Not to be confused with Global Region, global regions have no physical area. They do not contain any points. The global region does use the GlobalProtectedRegion, but other regions can also utilize this class (users can create them by using the -g switch on /rg define).

These regions are usually used to create template regions for parenting.

ProtectedRegion region = new GlobalProtectedRegion("template");

Spatial Queries

There are a few methods to perform spatial queries on a specific region.

Hint

If you are interested in performing spatial queries on all regions, see Spatial Queries.

Testing Point Containment

boolean contains(BlockVector3) can be used to test whether a region contains a particular point.

Example: Seeing whether a region contains (20, 0, 30)

region.contains(BlockVector3.at(20, 0, 30));

Finding Intersecting Regions

The getIntersectingRegions(Collection<ProtectedRegion>) method call can be used to return a list of intersecting regions. These regions do not have to be fully contained.

Example: Seeing which regions overlap with spawn

List<ProtectedRegion> candidates = Lists.newArrayList();
candidates.add(mall);
candidates.add(hospital);

List<ProtectedRegion> overlapping = spawn.getIntersectingRegions(candidates);

Dirty Flag

Whenever changes are made to a region object, a “dirty” flag (not to be confused with region flags) is set on the region. This can be tested with isDirty(), and it is used by region managers to know which regions need to be saved.