Compare commits

..
Author SHA1 Message Date
Wyatt Childers c95f52a303 Allow set flags to be manipulate via keywords
This adds support for updating an existing region, so that
if you have a long list of items in a set flag, such as
`deny-spawn` you can add or remove items, rather than overwrite.

Example:
```
/rg flag test deny-spawn add creeper
/rg flag test deny-spawn remove zombie
```
2020-01-14 22:56:04 -05:00
25 changed files with 308 additions and 1126 deletions

No files matched your search

@@ -24,7 +24,6 @@ import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.weather.WeatherTypes;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import io.papermc.lib.PaperLib;
import org.bukkit.BanList.Type;
import org.bukkit.Bukkit;
@@ -55,16 +54,6 @@ public class BukkitPlayer extends com.sk89q.worldedit.bukkit.BukkitPlayer implem
return name;
}
@Override
public String getDefaultNamespace() {
// TODO: Add a per player override
boolean useNamespaces = WorldGuard.getInstance().getPlatform().getGlobalStateManager().useNamespaces;
if (useNamespaces) {
return getUniqueId().toString();
}
return null;
}
@Override
public boolean hasGroup(String group) {
return plugin.inGroup(getPlayer(), group);
@@ -31,29 +31,6 @@ import java.util.List;
public interface LocalPlayer extends Player, RegionAssociable {
/**
* Returns the default namespace for this player.
*
* @return the default namespace.
*/
String getDefaultNamespace();
default boolean isDefaultNamespace(String otherNamespace) {
String namespace = getDefaultNamespace();
// If both are null, they're the same (the global)
if (namespace == null && otherNamespace == null) {
return true;
}
// If only one is null, they're a mismatch
if (namespace == null || otherNamespace == null) {
return false;
}
// Compare string equality
return namespace.equalsIgnoreCase(otherNamespace);
}
/**
* Returns true if this player is inside a group.
*
@@ -32,7 +32,6 @@ import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import com.sk89q.worldguard.protection.util.DomainInputResolver;
import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy;
@@ -51,13 +50,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "nw:",
desc = "Add a member to a region",
min = 2)
public void addMember(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void addMember(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
ProtectedRegion region = checkExistingRegion(manager, id, true);
// Check permissions
if (!getPermissionModel(sender).mayAddMembers(region)) {
@@ -70,11 +69,10 @@ public class MemberCommands extends RegionCommandsBase {
resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_ONLY);
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Adding members to the region '%s' on '%s'", friendlyName, world.getName());
final String description = String.format("Adding members to the region '%s' on '%s'", region.getId(), world.getName());
AsyncCommandBuilder.wrap(resolver, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("Region '%s' updated with new members.", friendlyName), region.getMembers()::addAll)
.onSuccess(String.format("Region '%s' updated with new members.", region.getId()), region.getMembers()::addAll)
.onFailure("Failed to add new members", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -84,14 +82,15 @@ public class MemberCommands extends RegionCommandsBase {
flags = "nw:",
desc = "Add an owner to a region",
min = 2)
public void addOwner(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void addOwner(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
ProtectedRegion region = checkExistingRegion(manager, id, true);
// Check permissions
if (!getPermissionModel(sender).mayAddOwners(region)) {
@@ -104,11 +103,10 @@ public class MemberCommands extends RegionCommandsBase {
resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_ONLY);
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Adding owners to the region '%s' on '%s'", friendlyName, world.getName());
final String description = String.format("Adding owners to the region '%s' on '%s'", region.getId(), world.getName());
AsyncCommandBuilder.wrap(checkedAddOwners(sender, manager, region, world, resolver), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("Region '%s' updated with new owners.", friendlyName), region.getOwners()::addAll)
.onSuccess(String.format("Region '%s' updated with new owners.", region.getId()), region.getOwners()::addAll)
.onFailure("Failed to add new owners", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -151,13 +149,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "naw:",
desc = "Remove an owner to a region",
min = 1)
public void removeMember(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void removeMember(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
ProtectedRegion region = checkExistingRegion(manager, id, true);
// Check permissions
if (!getPermissionModel(sender).mayRemoveMembers(region)) {
@@ -180,12 +178,11 @@ public class MemberCommands extends RegionCommandsBase {
callable = resolver;
}
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Removing members from the region '%s' on '%s'", friendlyName, world.getName());
final String description = String.format("Removing members from the region '%s' on '%s'", region.getId(), world.getName());
AsyncCommandBuilder.wrap(callable, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... querying player names...)")
.onSuccess(String.format("Region '%s' updated with members removed.", friendlyName), region.getMembers()::removeAll)
.onSuccess(String.format("Region '%s' updated with members removed.", region.getId()), region.getMembers()::removeAll)
.onFailure("Failed to remove members", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -195,13 +192,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "naw:",
desc = "Remove an owner to a region",
min = 1)
public void removeOwner(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void removeOwner(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
ProtectedRegion region = checkExistingRegion(manager, id, true);
// Check permissions
if (!getPermissionModel(sender).mayRemoveOwners(region)) {
@@ -224,12 +221,11 @@ public class MemberCommands extends RegionCommandsBase {
callable = resolver;
}
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Removing owners from the region '%s' on '%s'", friendlyName, world.getName());
final String description = String.format("Removing owners from the region '%s' on '%s'", region.getId(), world.getName());
AsyncCommandBuilder.wrap(callable, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... querying player names...)")
.onSuccess(String.format("Region '%s' updated with owners removed.", friendlyName), region.getOwners()::removeAll)
.onSuccess(String.format("Region '%s' updated with owners removed.", region.getId()), region.getOwners()::removeAll)
.onFailure("Failed to remove owners", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -32,7 +32,6 @@ import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.LabelFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
@@ -45,6 +44,7 @@ import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.commands.CommandUtils;
import com.sk89q.worldguard.commands.task.RegionAdder;
import com.sk89q.worldguard.commands.task.RegionLister;
import com.sk89q.worldguard.commands.task.RegionManagerLoader;
@@ -68,8 +68,11 @@ import com.sk89q.worldguard.protection.managers.migration.MigrationException;
import com.sk89q.worldguard.protection.managers.migration.UUIDMigration;
import com.sk89q.worldguard.protection.managers.storage.DriverType;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.regions.*;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion.CircularInheritanceException;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.util.Enums;
@@ -130,7 +133,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "ng",
desc = "Defines a region",
min = 1)
public void define(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void define(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender);
@@ -139,12 +142,12 @@ public final class RegionCommands extends RegionCommandsBase {
throw new CommandPermissionsException();
}
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
String id = checkRegionId(args.getString(0), false);
World world = player.getWorld();
RegionManager manager = checkRegionManager(world);
checkRegionDoesNotExist(sender, manager, id, true);
checkRegionDoesNotExist(manager, id, true);
ProtectedRegion region;
@@ -157,18 +160,17 @@ public final class RegionCommands extends RegionCommandsBase {
RegionAdder task = new RegionAdder(manager, region);
task.addOwnersFromCommand(args, 2);
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Adding region '%s'", friendlyName);
final String description = String.format("Adding region '%s'", region.getId());
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess((Component) null,
t -> {
sender.print(String.format("A new region has been made named '%s'.", friendlyName));
sender.print(String.format("A new region has been made named '%s'.", region.getId()));
warnAboutDimensions(sender, region);
informNewUser(sender, manager, region);
checkSpawnOverlap(sender, world, region);
})
.onFailure(String.format("Failed to add the region '%s'", friendlyName), worldGuard.getExceptionConverter())
.onFailure(String.format("Failed to add the region '%s'", region.getId()), worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -184,17 +186,17 @@ public final class RegionCommands extends RegionCommandsBase {
desc = "Re-defines the shape of a region",
flags = "g",
min = 1, max = 1)
public void redefine(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void redefine(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender);
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
String id = checkRegionId(args.getString(0), false);
World world = player.getWorld();
RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
ProtectedRegion existing = checkExistingRegion(manager, id, false);
// Check permissions
if (!getPermissionModel(player).mayRedefine(existing)) {
@@ -213,19 +215,18 @@ public final class RegionCommands extends RegionCommandsBase {
RegionAdder task = new RegionAdder(manager, region);
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Updating region '%s'", friendlyName);
final String description = String.format("Updating region '%s'", region.getId());
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... " + description + ")")
.onSuccess((Component) null,
t -> {
player.print(String.format("Region '%s' has been updated with a new area.", friendlyName));
player.print(String.format("Region '%s' has been updated with a new area.", region.getId()));
warnAboutDimensions(player, region);
informNewUser(player, manager, region);
checkSpawnOverlap(sender, world, region);
})
.onFailure(String.format("Failed to update the region '%s'", friendlyName), worldGuard.getExceptionConverter())
.onFailure(String.format("Failed to update the region '%s'", region.getId()), worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -243,7 +244,7 @@ public final class RegionCommands extends RegionCommandsBase {
usage = "<id>",
desc = "Claim a region",
min = 1, max = 1)
public void claim(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void claim(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender);
@@ -254,11 +255,11 @@ public final class RegionCommands extends RegionCommandsBase {
throw new CommandPermissionsException();
}
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
String id = checkRegionId(args.getString(0), false);
RegionManager manager = checkRegionManager(player.getWorld());
checkRegionDoesNotExist(sender, manager, id, false);
checkRegionDoesNotExist(manager, id, false);
ProtectedRegion region = checkRegionFromSelection(player, id);
WorldConfiguration wcfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(player.getWorld());
@@ -320,12 +321,11 @@ public final class RegionCommands extends RegionCommandsBase {
task.setLocatorPolicy(UserLocatorPolicy.UUID_ONLY);
task.setOwnersInput(new String[]{player.getName()});
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Claiming region '%s'", friendlyName);
final String description = String.format("Claiming region '%s'", id);
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... " + description + ")")
.onSuccess(TextComponent.of(String.format("A new region has been claimed named '%s'.", friendlyName)), null)
.onSuccess(TextComponent.of(String.format("A new region has been claimed named '%s'.", id)), null)
.onFailure("Failed to claim region", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
}
@@ -341,7 +341,7 @@ public final class RegionCommands extends RegionCommandsBase {
usage = "[id]",
desc = "Load a region as a WorldEdit selection",
min = 0, max = 1)
public void select(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void select(CommandContext args, Actor sender) throws CommandException {
LocalPlayer player = worldGuard.checkPlayer(sender);
RegionManager manager = checkRegionManager(player.getWorld());
ProtectedRegion existing;
@@ -350,8 +350,7 @@ public final class RegionCommands extends RegionCommandsBase {
if (args.argsLength() == 0) {
existing = checkRegionStandingIn(manager, player, "/rg select %id%");
} else {
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
existing = checkExistingRegion(sender, manager, id);
existing = checkExistingRegion(manager, args.getString(0), false);
}
// Check permissions
@@ -375,7 +374,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "usw:",
desc = "Get information about a region",
min = 0, max = 1)
public void info(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void info(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -393,8 +392,7 @@ public final class RegionCommands extends RegionCommandsBase {
existing = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg info -w \"" + world.getName() + "\" %id%" + (args.hasFlag('u') ? " -u" : "") + (args.hasFlag('s') ? " -s" : ""));
} else { // Get region from the ID
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
existing = checkExistingRegion(sender, manager, id);
existing = checkExistingRegion(manager, args.getString(0), true);
}
// Check permissions
@@ -490,7 +488,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "g:w:eh:",
desc = "Set flags",
min = 2)
public void flag(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void flag(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -510,13 +508,13 @@ public final class RegionCommands extends RegionCommandsBase {
// Lookup the existing region
RegionManager manager = checkRegionManager(world);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
ProtectedRegion existing = checkExistingRegion(manager, args.getString(0), true);
// Check permissions
if (!permModel.maySetFlag(existing)) {
throw new CommandPermissionsException();
}
String regionId = existing.getId();
Flag<?> foundFlag = Flags.fuzzyMatchFlag(flagRegistry, flagName);
@@ -524,7 +522,7 @@ public final class RegionCommands extends RegionCommandsBase {
// can use, and do nothing afterwards
if (foundFlag == null) {
AsyncCommandBuilder.wrap(new FlagListBuilder(flagRegistry, permModel, existing, world,
id, sender, flagName), sender)
regionId, sender, flagName), sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), "Flag list for invalid flag command.")
.onSuccess((Component) null, sender::print)
.onFailure((Component) null, WorldGuard.getInstance().getExceptionConverter())
@@ -581,8 +579,7 @@ public final class RegionCommands extends RegionCommandsBase {
}
if (!args.hasFlag('h')) {
String friendlyName = id.getDisplayName(sender);
sender.print("Region flag " + foundFlag.getName() + " set on '" + friendlyName + "' to '" + value + "'.");
sender.print("Region flag " + foundFlag.getName() + " set on '" + regionId + "' to '" + value + "'.");
}
// No value? Clear the flag, if -g isn't specified
@@ -597,8 +594,7 @@ public final class RegionCommands extends RegionCommandsBase {
}
if (!args.hasFlag('h')) {
String friendlyName = id.getDisplayName(sender);
sender.print("Region flag " + foundFlag.getName() + " removed from '" + friendlyName + "'. (Any -g(roups) were also removed.)");
sender.print("Region flag " + foundFlag.getName() + " removed from '" + regionId + "'. (Any -g(roups) were also removed.)");
}
}
@@ -634,7 +630,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "p:w:",
desc = "View region flags",
min = 0, max = 2)
public void flagHelper(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void flagHelper(CommandContext args, Actor sender) throws CommandException {
World world = checkWorld(args, sender, 'w'); // Get the world
// Lookup the existing region
@@ -648,8 +644,7 @@ public final class RegionCommands extends RegionCommandsBase {
region = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg flags -w \"" + world.getName() + "\" %id%");
} else { // Get region from the ID
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
region = checkExistingRegion(sender, manager, id);
region = checkExistingRegion(manager, args.getString(0), true);
}
final RegionPermissionModel perms = getPermissionModel(sender);
@@ -685,7 +680,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "w:",
desc = "Set the priority of a region",
min = 2, max = 2)
public void setPriority(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void setPriority(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -693,8 +688,7 @@ public final class RegionCommands extends RegionCommandsBase {
// Lookup the existing region
RegionManager manager = checkRegionManager(world);
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
ProtectedRegion existing = checkExistingRegion(manager, args.getString(0), false);
// Check permissions
if (!getPermissionModel(sender).maySetPriority(existing)) {
@@ -703,8 +697,7 @@ public final class RegionCommands extends RegionCommandsBase {
existing.setPriority(priority);
String friendlyName = id.getDisplayName(sender);
sender.print("Priority of '" + friendlyName + "' set to " + priority + " (higher numbers override).");
sender.print("Priority of '" + existing.getId() + "' set to " + priority + " (higher numbers override).");
}
/**
@@ -719,7 +712,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "w:",
desc = "Set the parent of a region",
min = 1, max = 2)
public void setParent(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void setParent(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -730,11 +723,9 @@ public final class RegionCommands extends RegionCommandsBase {
RegionManager manager = checkRegionManager(world);
// Get parent and child
RegionIdentifier childId = processRegionId(sender, args.getString(0), false);
child = checkExistingRegion(sender, manager, childId);
child = checkExistingRegion(manager, args.getString(0), false);
if (args.argsLength() == 2) {
RegionIdentifier parentId = processRegionId(sender, args.getString(1), false);
parent = checkExistingRegion(sender, manager, parentId);
parent = checkExistingRegion(manager, args.getString(1), false);
} else {
parent = null;
}
@@ -748,15 +739,11 @@ public final class RegionCommands extends RegionCommandsBase {
child.setParent(parent);
} catch (CircularInheritanceException e) {
// Tell the user what's wrong
assert parent != null;
String parentFriendlyName = parent.getIdentifier().getDisplayName(sender);
String childFriendlyName = childId.getDisplayName(sender);
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), parent, null, sender);
printout.append(ErrorFormat.wrap("Uh oh! Setting '", parentFriendlyName, "' to be the parent of '", childFriendlyName,
assert parent != null;
printout.append(ErrorFormat.wrap("Uh oh! Setting '", parent.getId(), "' to be the parent of '", child.getId(),
"' would cause circular inheritance.")).newline();
printout.append(SubtleFormat.wrap("(Current inheritance on '", parentFriendlyName, "':")).newline();
printout.append(SubtleFormat.wrap("(Current inheritance on '", parent.getId(), "':")).newline();
printout.appendParentTree(true);
printout.append(SubtleFormat.wrap(")"));
printout.send(sender);
@@ -764,9 +751,8 @@ public final class RegionCommands extends RegionCommandsBase {
}
// Tell the user the current inheritance
String childFriendlyName = childId.getDisplayName(sender);
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), child, null, sender);
printout.append(TextComponent.of("Inheritance set for region '" + childFriendlyName + "'.", TextColor.LIGHT_PURPLE));
printout.append(TextComponent.of("Inheritance set for region '" + child.getId() + "'.", TextColor.LIGHT_PURPLE));
if (parent != null) {
printout.newline();
printout.append(SubtleFormat.wrap("(Current inheritance:")).newline();
@@ -790,7 +776,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "fuw:",
desc = "Remove a region",
min = 1, max = 1)
public void remove(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void remove(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -799,8 +785,7 @@ public final class RegionCommands extends RegionCommandsBase {
// Lookup the existing region
RegionManager manager = checkRegionManager(world);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
ProtectedRegion existing = checkExistingRegion(manager, args.getString(0), true);
// Check permissions
if (!getPermissionModel(sender).mayDelete(existing)) {
@@ -817,15 +802,12 @@ public final class RegionCommands extends RegionCommandsBase {
task.setRemovalStrategy(RemovalStrategy.UNSET_PARENT_IN_CHILDREN);
}
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Removing region '%s' in '%s'", friendlyName, world.getName());
final String description = String.format("Removing region '%s' in '%s'", existing.getId(), world.getName());
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), description)
.sendMessageAfterDelay("Please wait... removing region.")
.onSuccess((Component) null, removed -> sender.print(TextComponent.of(
"Successfully removed " + removed.stream()
.map((r) -> r.getIdentifier().getDisplayName(sender))
.collect(Collectors.joining(", ")) + ".",
"Successfully removed " + removed.stream().map(ProtectedRegion::getId).collect(Collectors.joining(", ")) + ".",
TextColor.LIGHT_PURPLE)))
.onFailure("Failed to remove region", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
@@ -860,6 +842,10 @@ public final class RegionCommands extends RegionCommandsBase {
if (world != null) {
RegionManager manager = checkRegionManager(world);
if (manager == null) {
throw new CommandException("No region manager exists for world '" + world.getName() + "'.");
}
final String description = String.format("Loading region data for '%s'.", world.getName());
AsyncCommandBuilder.wrap(new RegionManagerLoader(manager), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
@@ -916,6 +902,10 @@ public final class RegionCommands extends RegionCommandsBase {
if (world != null) {
RegionManager manager = checkRegionManager(world);
if (manager == null) {
throw new CommandException("No region manager exists for world '" + world.getName() + "'.");
}
final String description = String.format("Saving region data for '%s'.", world.getName());
AsyncCommandBuilder.wrap(new RegionManagerSaver(manager), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
@@ -1078,15 +1068,14 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "sw:",
desc = "Teleports you to the location associated with the region.",
min = 1, max = 1)
public void teleport(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void teleport(CommandContext args, Actor sender) throws CommandException {
LocalPlayer player = worldGuard.checkPlayer(sender);
Location teleportLocation;
// Lookup the existing region
World world = checkWorld(args, player, 'w');
RegionManager regionManager = checkRegionManager(world);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion existing = checkExistingRegion(sender, regionManager, id);
ProtectedRegion existing = checkExistingRegion(regionManager, args.getString(0), true);
// Check permissions
if (!getPermissionModel(player).mayTeleportTo(existing)) {
@@ -1109,10 +1098,9 @@ public final class RegionCommands extends RegionCommandsBase {
}
}
String friendlyName = id.getDisplayName(sender);
player.teleport(teleportLocation,
"Teleported you to the region '" + friendlyName + "'.",
"Unable to teleport to region '" + friendlyName + "'.");
"Teleported you to the region '" + existing.getId() + "'.",
"Unable to teleport to region '" + existing.getId() + "'.");
}
@Command(aliases = {"toggle-bypass", "bypass"},
@@ -1135,12 +1123,12 @@ public final class RegionCommands extends RegionCommandsBase {
private final RegionPermissionModel permModel;
private final ProtectedRegion existing;
private final World world;
private final RegionIdentifier regionId;
private final String regionId;
private final Actor sender;
private final String flagName;
FlagListBuilder(FlagRegistry flagRegistry, RegionPermissionModel permModel, ProtectedRegion existing,
World world, RegionIdentifier regionId, Actor sender, String flagName) {
World world, String regionId, Actor sender, String flagName) {
this.flagRegistry = flagRegistry;
this.permModel = permModel;
this.existing = existing;
@@ -1172,10 +1160,9 @@ public final class RegionCommands extends RegionCommandsBase {
for (int i = 0; i < flagList.size(); i++) {
String flag = flagList.get(i);
String qualifiedName = regionId.getQualifiedName();
builder.append(TextComponent.of(flag, i % 2 == 0 ? TextColor.GRAY : TextColor.WHITE)
.hoverEvent(clickToSet).clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg flag -w \"" + world.getName() + "\" " + qualifiedName + " " + flag + " ")));
"/rg flag -w \"" + world.getName() + "\" " + regionId + " " + flag + " ")));
if (i < flagList.size() + 1) {
builder.append(TextComponent.of(", "));
}
@@ -1185,12 +1172,10 @@ public final class RegionCommands extends RegionCommandsBase {
.append(TextComponent.newline())
.append(builder.build());
if (sender.isPlayer()) {
String friendlyName = regionId.getDisplayName(sender);
String qualifiedName = regionId.getQualifiedName();
return ret.append(TextComponent.of("Or use the command ", TextColor.LIGHT_PURPLE)
.append(TextComponent.of("/rg flags " + friendlyName, TextColor.AQUA)
.append(TextComponent.of("/rg flags " + regionId, TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg flags -w \"" + world.getName() + "\" " + qualifiedName))));
"/rg flags -w \"" + world.getName() + "\" " + regionId))));
}
return ret;
}
@@ -33,13 +33,13 @@ import com.sk89q.worldedit.regions.Polygonal2DRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
@@ -49,13 +49,13 @@ import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.FlagContext;
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.*;
import com.sk89q.worldguard.util.profile.Profile;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
class RegionCommandsBase {
@@ -77,9 +77,9 @@ class RegionCommandsBase {
* Gets the world from the given flag, or falling back to the the current player
* if the sender is a player, otherwise reporting an error.
*
* @param args the arguments
* @param args the arguments
* @param sender the sender
* @param flag the flag (such as 'w')
* @param flag the flag (such as 'w')
* @return a world
* @throws CommandException on error
*/
@@ -95,188 +95,26 @@ class RegionCommandsBase {
}
}
/**
* Validate a region name.
*
* @param name the name
* @param allowGlobal whether __global__ is allowed
* @throws CommandException thrown on an error
*/
protected static void checkName(String name, boolean allowGlobal) throws CommandException {
if (!RegionIdentifier.isValidName(name)) {
throw new CommandException(
"The region name of '" + name + "' contains characters that are not allowed.");
}
if (!allowGlobal && name.equalsIgnoreCase("__global__")) { // Sorry, no global
throw new CommandException(
"Sorry, you can't use __global__ here.");
}
}
/**
* Validate a region ID.
*
* @param id the id
* @param id the id
* @param allowGlobal whether __global__ is allowed
* @return the id given
* @throws CommandException thrown on an error
*/
@Deprecated
protected static String checkRegionId(String id, boolean allowGlobal) throws CommandException {
checkName(id, allowGlobal);
return id;
}
/**
* Validate a region namespace.
*
* @param namespace the namespace name
* @throws CommandException thrown on an error
*/
protected static void checkNamespace(String namespace) throws CommandException {
if (!RegionIdentifier.isValidNamespace(namespace)) {
if (!ProtectedRegion.isValidId(id)) {
throw new CommandException(
"The region namespace of '" + namespace + "' contains characters that are not allowed.");
}
}
/**
* Get the unqualified name from a possibly qualified region identifier.
*
* @param id the unprocessed region identifier
* @return the unqualified name, or an empty string if not present
*/
protected static String getUnqualifiedName(String id) {
int namespaceSeparatorIndex = id.lastIndexOf(':');
if (namespaceSeparatorIndex == -1) {
return id;
"The region name of '" + id + "' contains characters that are not allowed.");
}
int unqualifiedNameStartIndex = namespaceSeparatorIndex + 1;
if (unqualifiedNameStartIndex == id.length()) {
return "";
if (!allowGlobal && id.equalsIgnoreCase("__global__")) { // Sorry, no global
throw new CommandException(
"Sorry, you can't use __global__ here.");
}
return id.substring(unqualifiedNameStartIndex);
}
/**
* Get the namespace name from a possibly qualified region identifier.
*
* @param id the unprocessed region identifier
* @return an optional containing the namespace name, or an empty string if qualified,
* if not qualified, an empty optional is returned
*/
protected static Optional<String> getNamespace(String id) {
int namespaceSeparatorIndex = id.lastIndexOf(':');
if (namespaceSeparatorIndex == -1) {
return Optional.empty();
}
return Optional.of(id.substring(0, namespaceSeparatorIndex));
}
private static class InvalidMacroException extends RuntimeException {
public InvalidMacroException(String message) {
super(message);
}
}
/***
* Expand macros in the namespace name.
*
* @param namespace the unexpanded namespace name
* @return the expanded namespace name
*/
protected static String expandNamespace(String namespace) {
if (namespace.startsWith("#")) {
String playerName = namespace.substring(1);
try {
Profile profile = WorldGuard.getInstance().getProfileService().findByName(playerName);
if (profile != null) {
return profile.getUniqueId().toString();
}
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
throw new InvalidMacroException("Macro unresolvable: " + namespace);
}
return namespace;
}
/**
* Get the macro expanded namespace name from a possibly qualified region identifier.
*
* @param id the unprocessed region identifier
* @return an optional containing the expanded namespace name, or an empty string if qualified,
* if not qualified, an empty optional is returned
*/
protected static Optional<String> getExpandedNamespace(String id) throws CommandException {
try {
return getNamespace(id).map(RegionCommandsBase::expandNamespace);
} catch (InvalidMacroException ex) {
throw new CommandException(ex.getMessage());
}
}
/**
* Get the default namespace for a given actor.
*
* @param sender the sender who's default namespace we intend to retrieve.
* @return the default namespace
*/
protected static String getDefaultNamespace(Actor sender) {
if (sender instanceof LocalPlayer) {
return ((LocalPlayer) sender).getDefaultNamespace();
}
return null;
}
/**
* Process a possibly qualified region identifier into a RegionIdentifier.
*
* This method takes a possibly qualified region identifier, and processes it, expanding any namespace macros,
* running permissions checks, and validating the names for invalid character.
*
* @param sender the contextual sender to use for checks and macro expansions
* @param id the possibly unqualified id
* @param allowGlobal whether or not this method should allow use of the name __global__ name
* @return the processed region id
* @throws AuthorizationException if a permission check fails
* @throws CommandException if a name validation check fails
*/
protected static RegionIdentifier processRegionId(Actor sender, String id, boolean allowGlobal) throws AuthorizationException, CommandException {
String unqualifiedName = getUnqualifiedName(id);
checkName(unqualifiedName, allowGlobal);
Optional<String> optProvidedNamespace = getExpandedNamespace(id);
String namespace = optProvidedNamespace.orElse(getDefaultNamespace(sender));
// TODO use more informative permission checks
// This needs checked as a special case, before namespace name validation.
if (namespace.equals("")) {
sender.checkPermission("worldguard.region.namespace.global");
return new RegionIdentifier(null, unqualifiedName);
}
checkNamespace(namespace);
try {
UUID namespacePlayerId = UUID.fromString(namespace);
if (!namespacePlayerId.equals(sender.getUniqueId())) {
sender.checkPermission("worldguard.region.namespace.player");
}
} catch (IllegalArgumentException ex) {
sender.checkPermission("worldguard.region.namespace.custom." + namespace);
}
return new RegionIdentifier(namespace, unqualifiedName);
return id;
}
/**
@@ -290,7 +128,6 @@ class RegionCommandsBase {
* @param allowGlobal true to allow selecting __global__
* @throws CommandException thrown if no region is found by the given name
*/
@Deprecated
protected static ProtectedRegion checkExistingRegion(RegionManager regionManager, String id, boolean allowGlobal) throws CommandException {
// Validate the id
checkRegionId(id, allowGlobal);
@@ -313,36 +150,6 @@ class RegionCommandsBase {
return region;
}
/**
* Get a protected region by a given name, otherwise throw a
* {@link CommandException}.
*
* <p>This also validates the region ID.</p>
*
* @param actor the associated player
* @param regionManager the region manager
* @param id the name to search
* @throws CommandException thrown if no region is found by the given name
*/
protected static ProtectedRegion checkExistingRegion(Actor actor, RegionManager regionManager, RegionIdentifier id) throws CommandException {
ProtectedRegion region = regionManager.getRegion(id);
// No region found!
if (region == null) {
// But we want a __global__, so let's create one
if (id.getQualifiedName().equals(":__global__")) {
region = new GlobalProtectedRegion(id);
regionManager.addRegion(region);
return region;
}
throw new CommandException(
"No region could be found with the name of '" + id.getDisplayName(actor) + "'.");
}
return region;
}
/**
* Get the region at the player's location, if possible.
@@ -397,12 +204,10 @@ class RegionCommandsBase {
builder.append(TextComponent.of(", "));
}
first = false;
RegionIdentifier id = region.getIdentifier();
TextComponent regionComp = TextComponent.of(id.getDisplayName(player), TextColor.AQUA);
TextComponent regionComp = TextComponent.of(region.getId(), TextColor.AQUA);
if (rgCmd != null && rgCmd.contains("%id%")) {
regionComp = regionComp.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to pick this region")))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, rgCmd.replace("%id%", id.getQualifiedName())));
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, rgCmd.replace("%id%", region.getId())));
}
builder.append(regionComp);
}
@@ -439,23 +244,10 @@ class RegionCommandsBase {
* @param id the ID
* @throws CommandException thrown if the ID already exists
*/
@Deprecated
protected static void checkRegionDoesNotExist(RegionManager manager, String id, boolean mayRedefine) throws CommandException {
checkRegionDoesNotExist(null, manager, new RegionIdentifier(id), mayRedefine);
}
/**
* Check that a region with the given ID does not already exist.
*
* @param actor the associated player
* @param manager the manager
* @param id the identifier
* @throws CommandException thrown if the ID already exists
*/
protected static void checkRegionDoesNotExist(Actor actor, RegionManager manager, RegionIdentifier id, boolean mayRedefine) throws CommandException {
if (manager.hasRegion(id)) {
throw new CommandException("A region with that name already exists. Please choose another name." +
(mayRedefine ? " To change the shape, use /region redefine " + id.getDisplayName(actor) + "." : ""));
(mayRedefine ? " To change the shape, use /region redefine " + id + "." : ""));
}
}
@@ -488,20 +280,7 @@ class RegionCommandsBase {
* @return a new region
* @throws CommandException thrown on an error
*/
@Deprecated
protected static ProtectedRegion checkRegionFromSelection(LocalPlayer player, String id) throws CommandException {
return checkRegionFromSelection(player, new RegionIdentifier(id));
}
/**
* Create a {@link ProtectedRegion} from the player's selection.
*
* @param player the player
* @param id the identifier of the new region
* @return a new region
* @throws CommandException thrown on an error
*/
protected static ProtectedRegion checkRegionFromSelection(LocalPlayer player, RegionIdentifier id) throws CommandException {
Region selection = checkSelection(player);
// Detect the type of region from WorldEdit
@@ -19,7 +19,6 @@
package com.sk89q.worldguard.commands.region;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.math.BlockVector3;
@@ -59,7 +58,6 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
@Nullable
private final ProfileCache cache;
private final TextComponentProducer builder = new TextComponentProducer();
private final Actor actor;
private final RegionPermissionModel perms;
/**
@@ -72,7 +70,6 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
this.world = world;
this.region = region;
this.cache = cache;
this.actor = actor;
this.perms = actor != null && actor.isPlayer() ? new RegionPermissionModel(actor) : null;
}
@@ -88,10 +85,8 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
*/
public void appendBasics() {
builder.append(TextComponent.of("Region: ", TextColor.BLUE));
RegionIdentifier id = region.getIdentifier();
builder.append(TextComponent.of(id.getDisplayName(actor), TextColor.YELLOW)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg info -w \"" + world + "\" " + id.getQualifiedName())));
builder.append(TextComponent.of(region.getId(), TextColor.YELLOW)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg info -w \"" + world + "\" " + region.getId())));
builder.append(TextComponent.of(" (type=", TextColor.GRAY));
builder.append(TextComponent.of(region.getType().getName()));
@@ -76,7 +76,6 @@ public abstract class ConfigurationManager {
public boolean migrateRegionsToUuid;
public boolean keepUnresolvedNames;
public boolean particleEffects;
public boolean useNamespaces;
@Unreported public Map<String, String> hostKeys = new HashMap<>();
public boolean hostKeysAllowFMLClients;
@@ -63,7 +63,6 @@ public abstract class YamlConfigurationManager extends ConfigurationManager {
usePlayerMove = config.getBoolean("use-player-move-event", true);
usePlayerTeleports = config.getBoolean("use-player-teleports", true);
particleEffects = config.getBoolean("use-particle-effects", true);
useNamespaces = config.getBoolean("use-namespaces", true);
deopOnJoin = config.getBoolean("security.deop-everyone-on-join", false);
blockInGameOp = config.getBoolean("security.block-in-game-op-command", false);
@@ -26,7 +26,6 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import javax.annotation.Nullable;
@@ -20,18 +20,25 @@
package com.sk89q.worldguard.protection.flags;
import com.google.common.collect.Sets;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Stores a set of types.
*/
public class SetFlag<T> extends Flag<Set<T>> {
private static final Pattern ANY_MODIFIER = Pattern.compile("^(add|sub|subtract|rem|remove) (.*)$");
private static final Pattern REMOVE_MODIFIERS = Pattern.compile("^(sub|subtract|rem|remove) (.*)$");
private Flag<T> subFlag;
public SetFlag(String name, RegionGroup defaultGroup, Flag<T> subFlag) {
@@ -60,10 +67,32 @@ public class SetFlag<T> extends Flag<Set<T>> {
return Sets.newHashSet();
} else {
Set<T> items = Sets.newHashSet();
boolean subtractive = false;
// If the input starts with particular keywords, attempt to load the existing values,
// and make this a modification, instead of an overwrite.
Matcher keywordMatcher = ANY_MODIFIER.matcher(input);
if (keywordMatcher.matches()) {
ProtectedRegion region = Objects.requireNonNull((ProtectedRegion) context.get("region"));
Set<T> existingValue = region.getFlag(this);
if (existingValue != null) {
items.addAll(existingValue);
}
subtractive = REMOVE_MODIFIERS.matcher(input).matches();
input = keywordMatcher.group(2);
}
for (String str : input.split(",")) {
FlagContext copy = context.copyWith(null, str, null);
items.add(subFlag.parseInput(copy));
T subFlagValue = subFlag.parseInput(copy);
if (subtractive) {
items.remove(subFlagValue);
} else {
items.add(subFlagValue);
}
}
return items;
@@ -34,7 +34,6 @@ import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import com.sk89q.worldguard.protection.util.RegionCollectionConsumer;
import com.sk89q.worldguard.util.Normal;
@@ -243,22 +242,10 @@ public final class RegionManager {
* @param id the name of the region
* @return true if this index contains the region
*/
@Deprecated
public boolean hasRegion(String id) {
return index.contains(id);
}
/**
* Return whether the index contains a region with the given identifier,
* with quality determined by {@link Normal}.
*
* @param id the region identifier
* @return true if this index contains the region
*/
public boolean hasRegion(RegionIdentifier id) {
return index.contains(id.getLegacyQualifiedName());
}
/**
* Get the region named by the given name (equality determined using
* {@link Normal}).
@@ -267,24 +254,11 @@ public final class RegionManager {
* @return a region or {@code null}
*/
@Nullable
@Deprecated
public ProtectedRegion getRegion(String id) {
checkNotNull(id);
return index.get(id);
}
/**
* Get the region named y the given id.
*
* @param id the region identifier
* @return a region or {@code null}
*/
@Nullable
public ProtectedRegion getRegion(RegionIdentifier id) {
checkNotNull(id);
return index.get(id.getLegacyQualifiedName());
}
/**
* @deprecated Use exact ids with {@link #getRegion}
*/
@@ -70,13 +70,12 @@ public class HashMapIndex extends AbstractRegionIndex implements ConcurrentRegio
region.setDirty(true);
synchronized (lock) {
String newFullId = region.getIdentifier().getLegacyQualifiedName();
String normalId = normalize(newFullId);
String normalId = normalize(region.getId());
ProtectedRegion existing = regions.get(normalId);
// Casing / form of ID has changed
if (existing != null && !existing.getIdentifier().getLegacyQualifiedName().equals(newFullId)) {
if (existing != null && !existing.getId().equals(region.getId())) {
removed.add(existing);
}
@@ -1,60 +0,0 @@
/*
* 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.protection.managers.storage.file;
import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.worldguard.domains.DefaultDomain;
import java.util.UUID;
import java.util.logging.Level;
class DomainParser {
public static class One {
public static DefaultDomain parseDomain(YAMLNode node) {
if (node == null) {
return new DefaultDomain();
}
DefaultDomain domain = new DefaultDomain();
for (String name : node.getStringList("players", null)) {
if (!name.isEmpty()) {
domain.addPlayer(name);
}
}
for (String stringId : node.getStringList("unique-ids", null)) {
try {
domain.addPlayer(UUID.fromString(stringId));
} catch (IllegalArgumentException e) {
YamlCommon.log.log(Level.WARNING, "Failed to parse UUID '" + stringId + "'", e);
}
}
for (String name : node.getStringList("groups", null)) {
if (!name.isEmpty()) {
domain.addGroup(name);
}
}
return domain;
}
}
}
@@ -1,34 +0,0 @@
/*
* 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.protection.managers.storage.file;
import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
class FlagParser {
public static class One {
public static void setFlags(FlagRegistry flagRegistry, ProtectedRegion region, YAMLNode flagsData) {
if (flagsData != null) {
region.setFlags(flagRegistry.unmarshal(flagsData.getMap(), true));
}
}
}
}
@@ -1,59 +0,0 @@
/*
* 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.protection.managers.storage.file;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.representer.Representer;
import java.util.logging.Logger;
class YamlCommon {
public static final Logger log = Logger.getLogger(YamlRegionFile.class.getCanonicalName());
public static final Yaml ERROR_DUMP_YAML;
static {
DumperOptions options = new DumperOptions();
options.setIndent(4);
options.setDefaultFlowStyle(DumperOptions.FlowStyle.AUTO);
ERROR_DUMP_YAML = new Yaml(new SafeConstructor(), new Representer(), options);
}
public static final String YAML_GLOBAL_NAMESPACE_NAME = "__global_ns__";
private YamlCommon() {
}
/**
* Dump the given object as YAML for debugging purposes.
*
* @param object the object
* @return the YAML string or an error string if dumping fals
*/
public static String toYamlOutput(Object object) {
try {
return ERROR_DUMP_YAML.dump(object).replaceAll("(?m)^", "\t");
} catch (Throwable t) {
return "<error while dumping object>";
}
}
}
@@ -1,34 +0,0 @@
/*
* 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.protection.managers.storage.file;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.util.Set;
interface YamlReader {
public int getVersion();
default public boolean canLoad(YAMLProcessor config) {
return config.getInt("version", 1) == getVersion();
}
public Set<ProtectedRegion> load(FlagRegistry flagRegistry, YAMLProcessor config);
}
@@ -1,114 +0,0 @@
/*
* 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.protection.managers.storage.file;
import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabaseUtils;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.util.*;
import java.util.logging.Level;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldguard.protection.managers.storage.file.YamlCommon.log;
import static com.sk89q.worldguard.protection.managers.storage.file.YamlCommon.toYamlOutput;
class YamlReaderVersionOne implements YamlReader {
@Override
public int getVersion() {
return 1;
}
@Override
public Set<ProtectedRegion> load(FlagRegistry flagRegistry, YAMLProcessor config) {
Map<String, ProtectedRegion> loaded = new HashMap<>();
Map<String, YAMLNode> regionData = config.getNodes("regions");
if (regionData == null) {
return Collections.emptySet(); // No regions are even configured
}
Map<ProtectedRegion, String> parentSets = new LinkedHashMap<>();
for (Map.Entry<String, YAMLNode> entry : regionData.entrySet()) {
String id = entry.getKey();
YAMLNode node = entry.getValue();
String type = node.getString("type");
ProtectedRegion region;
try {
if (type == null) {
log.warning("Undefined region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
continue;
} else if (type.equals("cuboid")) {
Vector3 pt1 = checkNotNull(node.getVector("min"));
Vector3 pt2 = checkNotNull(node.getVector("max"));
BlockVector3 min = pt1.getMinimum(pt2).toBlockPoint();
BlockVector3 max = pt1.getMaximum(pt2).toBlockPoint();
region = new ProtectedCuboidRegion(id, min, max);
} else if (type.equals("poly2d")) {
Integer minY = checkNotNull(node.getInt("min-y"));
Integer maxY = checkNotNull(node.getInt("max-y"));
List<BlockVector2> points = node.getBlockVector2List("points", null);
region = new ProtectedPolygonalRegion(id, points, minY, maxY);
} else if (type.equals("global")) {
region = new GlobalProtectedRegion(id);
} else {
log.warning("Unknown region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
continue;
}
Integer priority = checkNotNull(node.getInt("priority"));
region.setPriority(priority);
FlagParser.One.setFlags(flagRegistry, region, node.getNode("flags"));
region.setOwners(DomainParser.One.parseDomain(node.getNode("owners")));
region.setMembers(DomainParser.One.parseDomain(node.getNode("members")));
loaded.put(id, region);
String parentId = node.getString("parent");
if (parentId != null) {
parentSets.put(region, parentId);
}
} catch (NullPointerException e) {
log.log(Level.WARNING,
"Unexpected NullPointerException encountered during parsing for the region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) +
"\n\nNote: This region will disappear as a result!", e);
}
}
// Relink parents
RegionDatabaseUtils.relinkParents(loaded, parentSets);
return new HashSet<>(loaded.values());
}
}
@@ -1,120 +0,0 @@
/*
* 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.protection.managers.storage.file;
import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabaseUtils;
import com.sk89q.worldguard.protection.regions.*;
import java.util.*;
import java.util.logging.Level;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldguard.protection.managers.storage.file.YamlCommon.*;
class YamlReaderVersionTwo implements YamlReader {
@Override
public int getVersion() {
return 2;
}
@Override
public Set<ProtectedRegion> load(FlagRegistry flagRegistry, YAMLProcessor config) {
Map<String, ProtectedRegion> loaded = new HashMap<>();
Map<String, YAMLNode> regionData = config.getNodes("regions");
if (regionData == null) {
return Collections.emptySet(); // No regions are even configured
}
Map<ProtectedRegion, String> parentSets = new LinkedHashMap<>();
for (Map.Entry<String, YAMLNode> namespaceEntry : regionData.entrySet()) {
String namespaceKey = namespaceEntry.getKey();
String namespace = namespaceKey;
if (namespace.equals(YAML_GLOBAL_NAMESPACE_NAME)) {
namespace = null;
}
for (Map.Entry<String, Object> entry : namespaceEntry.getValue().getMap().entrySet()) {
String name = entry.getKey();
YAMLNode node = config.getNode("regions." + namespaceKey + "." + name);
String type = node.getString("type");
ProtectedRegion region;
RegionIdentifier id = new RegionIdentifier(namespace, name);
try {
if (type == null) {
log.warning("Undefined region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(node.getMap()) + "\n");
continue;
} else if (type.equals("cuboid")) {
Vector3 pt1 = checkNotNull(node.getVector("min"));
Vector3 pt2 = checkNotNull(node.getVector("max"));
BlockVector3 min = pt1.getMinimum(pt2).toBlockPoint();
BlockVector3 max = pt1.getMaximum(pt2).toBlockPoint();
region = new ProtectedCuboidRegion(id, min, max);
} else if (type.equals("poly2d")) {
Integer minY = checkNotNull(node.getInt("min-y"));
Integer maxY = checkNotNull(node.getInt("max-y"));
List<BlockVector2> points = node.getBlockVector2List("points", null);
region = new ProtectedPolygonalRegion(id, points, minY, maxY);
} else if (type.equals("global")) {
region = new GlobalProtectedRegion(id);
} else {
log.warning("Unknown region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(node.getMap()) + "\n");
continue;
}
Integer priority = checkNotNull(node.getInt("priority"));
region.setPriority(priority);
FlagParser.One.setFlags(flagRegistry, region, node.getNode("flags"));
region.setOwners(DomainParser.One.parseDomain(node.getNode("owners")));
region.setMembers(DomainParser.One.parseDomain(node.getNode("members")));
loaded.put(id.getLegacyQualifiedName(), region);
String parentQualifiedName = node.getString("parent");
if (parentQualifiedName != null) {
parentSets.put(region, parentQualifiedName);
}
} catch (NullPointerException e) {
log.log(Level.WARNING,
"Unexpected NullPointerException encountered during parsing for the region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(node.getMap()) +
"\n\nNote: This region will disappear as a result!", e);
}
}
}
// Relink parents
RegionDatabaseUtils.relinkParents(loaded, parentSets);
return new HashSet<>(loaded.values());
}
}
@@ -19,32 +19,56 @@
package com.sk89q.worldguard.protection.managers.storage.file;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.util.yaml.YAMLFormat;
import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.FlagUtil;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabaseUtils;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.*;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.parser.ParserException;
import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldguard.protection.managers.storage.file.YamlCommon.YAML_GLOBAL_NAMESPACE_NAME;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A store that persists regions in a YAML-encoded file.
*/
public class YamlRegionFile implements RegionDatabase {
private static final Logger log = Logger.getLogger(YamlRegionFile.class.getCanonicalName());
private static final Yaml ERROR_DUMP_YAML;
private static final String FILE_HEADER = "#\r\n" +
"# WorldGuard regions file\r\n" +
"#\r\n" +
@@ -57,19 +81,17 @@ public class YamlRegionFile implements RegionDatabase {
"# REMEMBER TO KEEP PERIODICAL BACKUPS.\r\n" +
"#";
private static final List<YamlReader> YAML_READERS = new ArrayList<>();
static {
// IMPORTANT: For best performance, add these in reverse order.
// We always want the latest version to be attempted first, so that once migrated, we are checking
// one version, not n.
YAML_READERS.add(new YamlReaderVersionTwo());
YAML_READERS.add(new YamlReaderVersionOne());
}
private final String name;
private final File file;
static {
DumperOptions options = new DumperOptions();
options.setIndent(4);
options.setDefaultFlowStyle(FlowStyle.AUTO);
ERROR_DUMP_YAML = new Yaml(new SafeConstructor(), new Representer(), options);
}
/**
* Create a new instance.
*
@@ -90,22 +112,80 @@ public class YamlRegionFile implements RegionDatabase {
@Override
public Set<ProtectedRegion> loadAll(FlagRegistry flagRegistry) throws StorageException {
Map<String, ProtectedRegion> loaded = new HashMap<>();
YAMLProcessor config = createYamlProcessor(file);
try {
config.load();
} catch (FileNotFoundException e) {
return new HashSet<>();
return new HashSet<>(loaded.values());
} catch (IOException | ParserException e) {
throw new StorageException("Failed to load region data from '" + file + "'", e);
}
for (YamlReader reader : YAML_READERS) {
if (reader.canLoad(config)) {
return reader.load(flagRegistry, config);
Map<String, YAMLNode> regionData = config.getNodes("regions");
if (regionData == null) {
return Collections.emptySet(); // No regions are even configured
}
Map<ProtectedRegion, String> parentSets = new LinkedHashMap<>();
for (Map.Entry<String, YAMLNode> entry : regionData.entrySet()) {
String id = entry.getKey();
YAMLNode node = entry.getValue();
String type = node.getString("type");
ProtectedRegion region;
try {
if (type == null) {
log.warning("Undefined region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
continue;
} else if (type.equals("cuboid")) {
Vector3 pt1 = checkNotNull(node.getVector("min"));
Vector3 pt2 = checkNotNull(node.getVector("max"));
BlockVector3 min = pt1.getMinimum(pt2).toBlockPoint();
BlockVector3 max = pt1.getMaximum(pt2).toBlockPoint();
region = new ProtectedCuboidRegion(id, min, max);
} else if (type.equals("poly2d")) {
Integer minY = checkNotNull(node.getInt("min-y"));
Integer maxY = checkNotNull(node.getInt("max-y"));
List<BlockVector2> points = node.getBlockVector2List("points", null);
region = new ProtectedPolygonalRegion(id, points, minY, maxY);
} else if (type.equals("global")) {
region = new GlobalProtectedRegion(id);
} else {
log.warning("Unknown region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
continue;
}
Integer priority = checkNotNull(node.getInt("priority"));
region.setPriority(priority);
setFlags(flagRegistry, region, node.getNode("flags"));
region.setOwners(parseDomain(node.getNode("owners")));
region.setMembers(parseDomain(node.getNode("members")));
loaded.put(id, region);
String parentId = node.getString("parent");
if (parentId != null) {
parentSets.put(region, parentId);
}
} catch (NullPointerException e) {
log.log(Level.WARNING,
"Unexpected NullPointerException encountered during parsing for the region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) +
"\n\nNote: This region will disappear as a result!", e);
}
}
throw new IllegalStateException("No YAML reader was registered that understands the saved region information");
// Relink parents
RegionDatabaseUtils.relinkParents(loaded, parentSets);
return new HashSet<>(loaded.values());
}
@Override
@@ -117,25 +197,13 @@ public class YamlRegionFile implements RegionDatabase {
config.clear();
config.setProperty("version", YAML_READERS.get(0).getVersion());
YAMLNode regionsNode = config.addNode("regions");
// Creates a mapping of existing namespace node names, to their underlying YAMLNode.
Map<String, YAMLNode> namespaceMap = new HashMap<>();
Map<String, Object> map = regionsNode.getMap();
for (ProtectedRegion region : regions) {
RegionIdentifier identifier = region.getIdentifier();
String internalNamespace = identifier.getNamespace().orElse(YAML_GLOBAL_NAMESPACE_NAME);
YAMLNode namespaceNode = namespaceMap.compute(internalNamespace, (ignored, existingNamespaceNode) -> {
if (existingNamespaceNode == null) {
existingNamespaceNode = regionsNode.addNode(internalNamespace);
}
return existingNamespaceNode;
});
YAMLNode node = namespaceNode.addNode(identifier.getName());
Map<String, Object> nodeMap = new HashMap<>();
map.put(region.getId(), nodeMap);
YAMLNode node = new YAMLNode(nodeMap, false);
if (region instanceof ProtectedCuboidRegion) {
ProtectedCuboidRegion cuboid = (ProtectedCuboidRegion) region;
@@ -170,7 +238,7 @@ public class YamlRegionFile implements RegionDatabase {
ProtectedRegion parent = region.getParent();
if (parent != null) {
node.setProperty("parent", parent.getIdentifier().getLegacyQualifiedName());
node.setProperty("parent", parent.getId());
}
}
@@ -189,10 +257,46 @@ public class YamlRegionFile implements RegionDatabase {
throw new DifferenceSaveException("Not supported");
}
private DefaultDomain parseDomain(YAMLNode node) {
if (node == null) {
return new DefaultDomain();
}
DefaultDomain domain = new DefaultDomain();
for (String name : node.getStringList("players", null)) {
if (!name.isEmpty()) {
domain.addPlayer(name);
}
}
for (String stringId : node.getStringList("unique-ids", null)) {
try {
domain.addPlayer(UUID.fromString(stringId));
} catch (IllegalArgumentException e) {
log.log(Level.WARNING, "Failed to parse UUID '" + stringId + "'", e);
}
}
for (String name : node.getStringList("groups", null)) {
if (!name.isEmpty()) {
domain.addGroup(name);
}
}
return domain;
}
private Map<String, Object> getFlagData(ProtectedRegion region) {
return FlagUtil.marshal(region.getFlags());
}
private void setFlags(FlagRegistry flagRegistry, ProtectedRegion region, YAMLNode flagsData) {
if (flagsData != null) {
region.setFlags(flagRegistry.unmarshal(flagsData.getMap(), true));
}
}
private Map<String, Object> getDomainData(DefaultDomain domain) {
Map<String, Object> domainData = new HashMap<>();
@@ -227,4 +331,19 @@ public class YamlRegionFile implements RegionDatabase {
checkNotNull(file);
return new YAMLProcessor(file, false, YAMLFormat.COMPACT);
}
/**
* Dump the given object as YAML for debugging purposes.
*
* @param object the object
* @return the YAML string or an error string if dumping fals
*/
private static String toYamlOutput(Object object) {
try {
return ERROR_DUMP_YAML.dump(object).replaceAll("(?m)^", "\t");
} catch (Throwable t) {
return "<error while dumping object>";
}
}
}
@@ -44,7 +44,6 @@ public class GlobalProtectedRegion extends ProtectedRegion {
*
* @param id the ID
*/
@Deprecated
public GlobalProtectedRegion(String id) {
this(id, false);
}
@@ -55,29 +54,7 @@ public class GlobalProtectedRegion extends ProtectedRegion {
* @param id the ID
* @param transientRegion whether this region should only be kept in memory and not be saved
*/
@Deprecated
public GlobalProtectedRegion(String id, boolean transientRegion) {
this(new RegionIdentifier(id), transientRegion);
}
/**
* Create a new instance.<br>
* Equivalent to {@link #GlobalProtectedRegion(String, boolean) GlobalProtectedRegion(id, false)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the region identifier
*/
public GlobalProtectedRegion(RegionIdentifier id) {
this(id, false);
}
/**
* Create a new instance.
*
* @param id the region identifier
* @param transientRegion whether this region should only be kept in memory and not be saved
*/
public GlobalProtectedRegion(RegionIdentifier id, boolean transientRegion) {
super(id, transientRegion);
min = BlockVector3.ZERO;
max = BlockVector3.ZERO;
@@ -47,7 +47,6 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
@Deprecated
public ProtectedCuboidRegion(String id, BlockVector3 pt1, BlockVector3 pt2) {
this(id, false, pt1, pt2);
}
@@ -60,34 +59,7 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
@Deprecated
public ProtectedCuboidRegion(String id, boolean transientRegion, BlockVector3 pt1, BlockVector3 pt2) {
this(new RegionIdentifier(id), transientRegion, pt1, pt2);
}
/**
* Construct a new instance of this cuboid region.<br>
* Equivalent to {@link #ProtectedCuboidRegion(RegionIdentifier, boolean, BlockVector3, BlockVector3)
* ProtectedCuboidRegion(id, false, pt1, pt2)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the region identifier
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
public ProtectedCuboidRegion(RegionIdentifier id, BlockVector3 pt1, BlockVector3 pt2) {
this(id, false, pt1, pt2);
}
/**
* Construct a new instance of this cuboid region.
*
* @param id the region identifier
* @param transientRegion whether this region should only be kept in memory and not be saved
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
public ProtectedCuboidRegion(RegionIdentifier id, boolean transientRegion, BlockVector3 pt1, BlockVector3 pt2) {
super(id, transientRegion);
setMinMaxPoints(pt1, pt2);
}
@@ -47,7 +47,6 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
@Deprecated
public ProtectedPolygonalRegion(String id, List<BlockVector2> points, int minY, int maxY) {
this(id, false, points, minY, maxY);
}
@@ -61,37 +60,7 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
@Deprecated
public ProtectedPolygonalRegion(String id, boolean transientRegion, List<BlockVector2> points, int minY, int maxY) {
this(new RegionIdentifier(id), transientRegion, points, minY, maxY);
}
/**
* Construct a new instance of this polygonal region.<br>
* Equivalent to {@link #ProtectedPolygonalRegion(RegionIdentifier, boolean, List, int, int)
* ProtectedPolygonalRegion(id, false, points, minY, maxY)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the region identifier
* @param points a {@link List} of points that this region should contain
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
public ProtectedPolygonalRegion(RegionIdentifier id, List<BlockVector2> points, int minY, int maxY) {
this(id, false, points, minY, maxY);
}
/**
* Construct a new instance of this polygonal region.
*
* @param id the region identifier
* @param transientRegion whether this region should only be kept in memory and not be saved
* @param points a {@link List} of points that this region should contain
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
public ProtectedPolygonalRegion(RegionIdentifier id, boolean transientRegion, List<BlockVector2> points,
int minY, int maxY) {
super(id, transientRegion);
ImmutableList<BlockVector2> immutablePoints = ImmutableList.copyOf(points);
setMinMaxPoints(immutablePoints, minY, maxY);
@@ -28,6 +28,7 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.util.ChangeTracked;
import com.sk89q.worldguard.util.Normal;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
@@ -36,6 +37,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
@@ -48,11 +50,12 @@ import javax.annotation.Nullable;
public abstract class ProtectedRegion implements ChangeTracked, Comparable<ProtectedRegion> {
public static final String GLOBAL_REGION = "__global__";
private static final Pattern VALID_ID_PATTERN = Pattern.compile("^[A-Za-z0-9_,'\\-\\+/]{1,}$");
protected BlockVector3 min;
protected BlockVector3 max;
private final RegionIdentifier id;
private final String id;
private final boolean transientRegion;
private int priority = 0;
private ProtectedRegion parent;
@@ -64,13 +67,18 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
/**
* Construct a new instance of this region.
*
* @param id the name information for this region
* @param id the name of this region
* @param transientRegion whether this region should only be kept in memory and not be saved
* @throws IllegalArgumentException thrown if the ID is invalid (see {@link #isValidId(String)}
*/
ProtectedRegion(RegionIdentifier id, boolean transientRegion) { // Package private because we can't have people creating their own region types
ProtectedRegion(String id, boolean transientRegion) { // Package private because we can't have people creating their own region types
checkNotNull(id);
this.id = id;
if (!isValidId(id)) {
throw new IllegalArgumentException("Invalid region ID: " + id);
}
this.id = Normal.normalize(id);
this.transientRegion = transientRegion;
}
@@ -111,17 +119,7 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
*
* @return the name
*/
@Deprecated
public String getId() {
return id.getLegacyQualifiedName();
}
/**
* Gets the identifier info for this region.
*
* @return the identifier info
*/
public RegionIdentifier getIdentifier() {
return id;
}
@@ -736,9 +734,9 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
* @param id the id to check
* @return whether the region id given is valid
*/
@Deprecated
public static boolean isValidId(String id) {
return RegionIdentifier.isValidName(id);
checkNotNull(id);
return VALID_ID_PATTERN.matcher(id).matches();
}
/**
@@ -1,147 +0,0 @@
/*
* 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.protection.regions;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.util.Normal;
import com.sk89q.worldguard.util.profile.Profile;
import javax.annotation.Nullable;
import java.util.Optional;
import java.util.UUID;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
public final class RegionIdentifier {
private static final Pattern VALID_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9_,'\\-\\+/]{1,}$");
private String namespace;
private String name;
/**
* Construct a new RegionIdentifier for describing region name information, using the global namespace.<br>
* Equivalent to {@link #RegionIdentifier(String, String) RegionIdentifier(null, name)}<br>
* <code>namespace</code> will be set to null.
*
* @param name the name for this region
* @throws IllegalArgumentException thrown if the name is invalid (see {@link #isValidName(String)}
*/
public RegionIdentifier(String name) {
this(null, name);
}
/**
* Construct a new RegionIdentifier for describing region name information.
*
* @param namespace the namespace name for this region, or null if there isn't one
* @param name the name for this region
* @throws IllegalArgumentException thrown if the namespace is invalid (see {@link #isValidNamespace(String)}
* @throws IllegalArgumentException thrown if the name is invalid (see {@link #isValidName(String)}
*/
public RegionIdentifier(@Nullable String namespace, String name) {
if (!isValidNamespace(name)) {
throw new IllegalArgumentException("Invalid region namespace: " + namespace);
}
if (!isValidName(name)) {
throw new IllegalArgumentException("Invalid region name: " + name);
}
this.namespace = namespace == null ? null : Normal.normalize(namespace);
this.name = Normal.normalize(name);
}
/**
* Returns the qualified name. This is incompatible with the legacy naming scheme, and
* should be used when interacting with the command system. This will ensure that the correct
* region is referenced regardless of the user's default namespace.
*
* @return the qualified name
*/
public String getQualifiedName() {
return getNamespace().orElse("") + ":" + name;
}
/**
* Returns the legacy qualified name. This is compatible with the legacy naming scheme, and
* should be used when interacting with the region manager via names.
*
* If you're using this outside of WorldGuard internals, you're doing something wrong.
*
* @return the legacy qualified name
*/
@Deprecated
public String getLegacyQualifiedName() {
return getNamespace().map((ns) -> ns + ':' + getName()).orElse(getName());
}
/**
* Compresses the name into a more user friendly macro based name.
*
* @param actor a player context
* @return the user friendly display name
*/
public String getDisplayName(Actor actor) {
if (actor instanceof LocalPlayer) {
LocalPlayer player = (LocalPlayer) actor;
if (player.isDefaultNamespace(namespace)) {
return name;
}
}
if (namespace != null) {
try {
UUID playerID = UUID.fromString(namespace);
Profile profile = WorldGuard.getInstance().getProfileCache().getIfPresent(playerID);
if (profile != null) {
return "#" + profile.getName() + ":" + name;
}
} catch (IllegalArgumentException ignored) {
}
}
// Fall back to the fully qualified name.
return getQualifiedName();
}
public Optional<String> getNamespace() {
return Optional.ofNullable(namespace);
}
public String getName() {
return name;
}
public static boolean isValidNamespace(String namespace) {
if (namespace == null) {
return true;
}
return VALID_NAME_PATTERN.matcher(namespace).matches();
}
public static boolean isValidName(String name) {
checkNotNull(name);
return VALID_NAME_PATTERN.matcher(name).matches();
}
}
@@ -64,11 +64,6 @@ public class TestPlayer extends AbstractPlayerActor implements LocalPlayer {
return uuid;
}
@Override
public String getDefaultNamespace() {
return null;
}
@Override
public boolean hasGroup(String group) {
return groups.contains(group.toLowerCase());