Implement region namespaces

This commit is contained in:
Wyatt Childers 2020-01-14 20:19:28 -05:00
parent b835ee39d5
commit ca7967085b
24 changed files with 1128 additions and 281 deletions

View File

@ -24,6 +24,7 @@ import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.weather.WeatherTypes; import com.sk89q.worldedit.world.weather.WeatherTypes;
import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import org.bukkit.BanList.Type; import org.bukkit.BanList.Type;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -54,6 +55,16 @@ public class BukkitPlayer extends com.sk89q.worldedit.bukkit.BukkitPlayer implem
return name; 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 @Override
public boolean hasGroup(String group) { public boolean hasGroup(String group) {
return plugin.inGroup(getPlayer(), group); return plugin.inGroup(getPlayer(), group);

View File

@ -31,6 +31,29 @@ import java.util.List;
public interface LocalPlayer extends Player, RegionAssociable { 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. * Returns true if this player is inside a group.
* *

View File

@ -32,6 +32,7 @@ import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.domains.DefaultDomain; import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion; 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;
import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy; import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy;
@ -50,13 +51,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "nw:", flags = "nw:",
desc = "Add a member to a region", desc = "Add a member to a region",
min = 2) min = 2)
public void addMember(CommandContext args, Actor sender) throws CommandException { public void addMember(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world); RegionManager manager = checkRegionManager(world);
ProtectedRegion region = checkExistingRegion(manager, id, true); RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
// Check permissions // Check permissions
if (!getPermissionModel(sender).mayAddMembers(region)) { if (!getPermissionModel(sender).mayAddMembers(region)) {
@ -69,10 +70,11 @@ public class MemberCommands extends RegionCommandsBase {
resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_ONLY); resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_ONLY);
final String description = String.format("Adding members to the region '%s' on '%s'", region.getId(), world.getName()); String friendlyName = id.getDisplayName(sender);
final String description = String.format("Adding members to the region '%s' on '%s'", friendlyName, world.getName());
AsyncCommandBuilder.wrap(resolver, sender) AsyncCommandBuilder.wrap(resolver, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description) .registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("Region '%s' updated with new members.", region.getId()), region.getMembers()::addAll) .onSuccess(String.format("Region '%s' updated with new members.", friendlyName), region.getMembers()::addAll)
.onFailure("Failed to add new members", worldGuard.getExceptionConverter()) .onFailure("Failed to add new members", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService()); .buildAndExec(worldGuard.getExecutorService());
} }
@ -82,15 +84,14 @@ public class MemberCommands extends RegionCommandsBase {
flags = "nw:", flags = "nw:",
desc = "Add an owner to a region", desc = "Add an owner to a region",
min = 2) min = 2)
public void addOwner(CommandContext args, Actor sender) throws CommandException { public void addOwner(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world); RegionManager manager = checkRegionManager(world);
ProtectedRegion region = checkExistingRegion(manager, id, true); RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
// Check permissions // Check permissions
if (!getPermissionModel(sender).mayAddOwners(region)) { if (!getPermissionModel(sender).mayAddOwners(region)) {
@ -103,10 +104,11 @@ public class MemberCommands extends RegionCommandsBase {
resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_ONLY); resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_ONLY);
final String description = String.format("Adding owners to the region '%s' on '%s'", region.getId(), world.getName()); String friendlyName = id.getDisplayName(sender);
final String description = String.format("Adding owners to the region '%s' on '%s'", friendlyName, world.getName());
AsyncCommandBuilder.wrap(checkedAddOwners(sender, manager, region, world, resolver), sender) AsyncCommandBuilder.wrap(checkedAddOwners(sender, manager, region, world, resolver), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description) .registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("Region '%s' updated with new owners.", region.getId()), region.getOwners()::addAll) .onSuccess(String.format("Region '%s' updated with new owners.", friendlyName), region.getOwners()::addAll)
.onFailure("Failed to add new owners", worldGuard.getExceptionConverter()) .onFailure("Failed to add new owners", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService()); .buildAndExec(worldGuard.getExecutorService());
} }
@ -149,13 +151,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "naw:", flags = "naw:",
desc = "Remove an owner to a region", desc = "Remove an owner to a region",
min = 1) min = 1)
public void removeMember(CommandContext args, Actor sender) throws CommandException { public void removeMember(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world); RegionManager manager = checkRegionManager(world);
ProtectedRegion region = checkExistingRegion(manager, id, true); RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
// Check permissions // Check permissions
if (!getPermissionModel(sender).mayRemoveMembers(region)) { if (!getPermissionModel(sender).mayRemoveMembers(region)) {
@ -178,11 +180,12 @@ public class MemberCommands extends RegionCommandsBase {
callable = resolver; callable = resolver;
} }
final String description = String.format("Removing members from the region '%s' on '%s'", region.getId(), world.getName()); String friendlyName = id.getDisplayName(sender);
final String description = String.format("Removing members from the region '%s' on '%s'", friendlyName, world.getName());
AsyncCommandBuilder.wrap(callable, sender) AsyncCommandBuilder.wrap(callable, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description) .registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... querying player names...)") .sendMessageAfterDelay("(Please wait... querying player names...)")
.onSuccess(String.format("Region '%s' updated with members removed.", region.getId()), region.getMembers()::removeAll) .onSuccess(String.format("Region '%s' updated with members removed.", friendlyName), region.getMembers()::removeAll)
.onFailure("Failed to remove members", worldGuard.getExceptionConverter()) .onFailure("Failed to remove members", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService()); .buildAndExec(worldGuard.getExecutorService());
} }
@ -192,13 +195,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "naw:", flags = "naw:",
desc = "Remove an owner to a region", desc = "Remove an owner to a region",
min = 1) min = 1)
public void removeOwner(CommandContext args, Actor sender) throws CommandException { public void removeOwner(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world); RegionManager manager = checkRegionManager(world);
ProtectedRegion region = checkExistingRegion(manager, id, true); RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
// Check permissions // Check permissions
if (!getPermissionModel(sender).mayRemoveOwners(region)) { if (!getPermissionModel(sender).mayRemoveOwners(region)) {
@ -221,11 +224,12 @@ public class MemberCommands extends RegionCommandsBase {
callable = resolver; callable = resolver;
} }
final String description = String.format("Removing owners from the region '%s' on '%s'", region.getId(), world.getName()); String friendlyName = id.getDisplayName(sender);
final String description = String.format("Removing owners from the region '%s' on '%s'", friendlyName, world.getName());
AsyncCommandBuilder.wrap(callable, sender) AsyncCommandBuilder.wrap(callable, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description) .registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... querying player names...)") .sendMessageAfterDelay("(Please wait... querying player names...)")
.onSuccess(String.format("Region '%s' updated with owners removed.", region.getId()), region.getOwners()::removeAll) .onSuccess(String.format("Region '%s' updated with owners removed.", friendlyName), region.getOwners()::removeAll)
.onFailure("Failed to remove owners", worldGuard.getExceptionConverter()) .onFailure("Failed to remove owners", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService()); .buildAndExec(worldGuard.getExecutorService());
} }

View File

@ -32,6 +32,7 @@ import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.util.Location; 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.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.LabelFormat; import com.sk89q.worldedit.util.formatting.component.LabelFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
@ -44,7 +45,6 @@ import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.commands.CommandUtils;
import com.sk89q.worldguard.commands.task.RegionAdder; import com.sk89q.worldguard.commands.task.RegionAdder;
import com.sk89q.worldguard.commands.task.RegionLister; import com.sk89q.worldguard.commands.task.RegionLister;
import com.sk89q.worldguard.commands.task.RegionManagerLoader; import com.sk89q.worldguard.commands.task.RegionManagerLoader;
@ -68,11 +68,8 @@ import com.sk89q.worldguard.protection.managers.migration.MigrationException;
import com.sk89q.worldguard.protection.managers.migration.UUIDMigration; import com.sk89q.worldguard.protection.managers.migration.UUIDMigration;
import com.sk89q.worldguard.protection.managers.storage.DriverType; import com.sk89q.worldguard.protection.managers.storage.DriverType;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver; import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion; import com.sk89q.worldguard.protection.regions.*;
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.ProtectedRegion.CircularInheritanceException;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy; import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy;
import com.sk89q.worldguard.session.Session; import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.util.Enums; import com.sk89q.worldguard.util.Enums;
@ -133,7 +130,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "ng", flags = "ng",
desc = "Defines a region", desc = "Defines a region",
min = 1) min = 1)
public void define(CommandContext args, Actor sender) throws CommandException { public void define(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender); LocalPlayer player = worldGuard.checkPlayer(sender);
@ -142,12 +139,12 @@ public final class RegionCommands extends RegionCommandsBase {
throw new CommandPermissionsException(); throw new CommandPermissionsException();
} }
String id = checkRegionId(args.getString(0), false); RegionIdentifier id = processRegionId(sender, args.getString(0), false);
World world = player.getWorld(); World world = player.getWorld();
RegionManager manager = checkRegionManager(world); RegionManager manager = checkRegionManager(world);
checkRegionDoesNotExist(manager, id, true); checkRegionDoesNotExist(sender, manager, id, true);
ProtectedRegion region; ProtectedRegion region;
@ -160,17 +157,18 @@ public final class RegionCommands extends RegionCommandsBase {
RegionAdder task = new RegionAdder(manager, region); RegionAdder task = new RegionAdder(manager, region);
task.addOwnersFromCommand(args, 2); task.addOwnersFromCommand(args, 2);
final String description = String.format("Adding region '%s'", region.getId()); String friendlyName = id.getDisplayName(sender);
final String description = String.format("Adding region '%s'", friendlyName);
AsyncCommandBuilder.wrap(task, sender) AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description) .registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess((Component) null, .onSuccess((Component) null,
t -> { t -> {
sender.print(String.format("A new region has been made named '%s'.", region.getId())); sender.print(String.format("A new region has been made named '%s'.", friendlyName));
warnAboutDimensions(sender, region); warnAboutDimensions(sender, region);
informNewUser(sender, manager, region); informNewUser(sender, manager, region);
checkSpawnOverlap(sender, world, region); checkSpawnOverlap(sender, world, region);
}) })
.onFailure(String.format("Failed to add the region '%s'", region.getId()), worldGuard.getExceptionConverter()) .onFailure(String.format("Failed to add the region '%s'", friendlyName), worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService()); .buildAndExec(worldGuard.getExecutorService());
} }
@ -186,17 +184,17 @@ public final class RegionCommands extends RegionCommandsBase {
desc = "Re-defines the shape of a region", desc = "Re-defines the shape of a region",
flags = "g", flags = "g",
min = 1, max = 1) min = 1, max = 1)
public void redefine(CommandContext args, Actor sender) throws CommandException { public void redefine(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender); LocalPlayer player = worldGuard.checkPlayer(sender);
String id = checkRegionId(args.getString(0), false); RegionIdentifier id = processRegionId(sender, args.getString(0), false);
World world = player.getWorld(); World world = player.getWorld();
RegionManager manager = checkRegionManager(world); RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(manager, id, false); ProtectedRegion existing = checkExistingRegion(sender, manager, id);
// Check permissions // Check permissions
if (!getPermissionModel(player).mayRedefine(existing)) { if (!getPermissionModel(player).mayRedefine(existing)) {
@ -215,18 +213,19 @@ public final class RegionCommands extends RegionCommandsBase {
RegionAdder task = new RegionAdder(manager, region); RegionAdder task = new RegionAdder(manager, region);
final String description = String.format("Updating region '%s'", region.getId()); String friendlyName = id.getDisplayName(sender);
final String description = String.format("Updating region '%s'", friendlyName);
AsyncCommandBuilder.wrap(task, sender) AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description) .registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... " + description + ")") .sendMessageAfterDelay("(Please wait... " + description + ")")
.onSuccess((Component) null, .onSuccess((Component) null,
t -> { t -> {
player.print(String.format("Region '%s' has been updated with a new area.", region.getId())); player.print(String.format("Region '%s' has been updated with a new area.", friendlyName));
warnAboutDimensions(player, region); warnAboutDimensions(player, region);
informNewUser(player, manager, region); informNewUser(player, manager, region);
checkSpawnOverlap(sender, world, region); checkSpawnOverlap(sender, world, region);
}) })
.onFailure(String.format("Failed to update the region '%s'", region.getId()), worldGuard.getExceptionConverter()) .onFailure(String.format("Failed to update the region '%s'", friendlyName), worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService()); .buildAndExec(worldGuard.getExecutorService());
} }
@ -244,7 +243,7 @@ public final class RegionCommands extends RegionCommandsBase {
usage = "<id>", usage = "<id>",
desc = "Claim a region", desc = "Claim a region",
min = 1, max = 1) min = 1, max = 1)
public void claim(CommandContext args, Actor sender) throws CommandException { public void claim(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender); LocalPlayer player = worldGuard.checkPlayer(sender);
@ -255,11 +254,11 @@ public final class RegionCommands extends RegionCommandsBase {
throw new CommandPermissionsException(); throw new CommandPermissionsException();
} }
String id = checkRegionId(args.getString(0), false); RegionIdentifier id = processRegionId(sender, args.getString(0), false);
RegionManager manager = checkRegionManager(player.getWorld()); RegionManager manager = checkRegionManager(player.getWorld());
checkRegionDoesNotExist(manager, id, false); checkRegionDoesNotExist(sender, manager, id, false);
ProtectedRegion region = checkRegionFromSelection(player, id); ProtectedRegion region = checkRegionFromSelection(player, id);
WorldConfiguration wcfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(player.getWorld()); WorldConfiguration wcfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(player.getWorld());
@ -321,11 +320,12 @@ public final class RegionCommands extends RegionCommandsBase {
task.setLocatorPolicy(UserLocatorPolicy.UUID_ONLY); task.setLocatorPolicy(UserLocatorPolicy.UUID_ONLY);
task.setOwnersInput(new String[]{player.getName()}); task.setOwnersInput(new String[]{player.getName()});
final String description = String.format("Claiming region '%s'", id); String friendlyName = id.getDisplayName(sender);
final String description = String.format("Claiming region '%s'", friendlyName);
AsyncCommandBuilder.wrap(task, sender) AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), description) .registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... " + description + ")") .sendMessageAfterDelay("(Please wait... " + description + ")")
.onSuccess(TextComponent.of(String.format("A new region has been claimed named '%s'.", id)), null) .onSuccess(TextComponent.of(String.format("A new region has been claimed named '%s'.", friendlyName)), null)
.onFailure("Failed to claim region", WorldGuard.getInstance().getExceptionConverter()) .onFailure("Failed to claim region", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService()); .buildAndExec(WorldGuard.getInstance().getExecutorService());
} }
@ -341,7 +341,7 @@ public final class RegionCommands extends RegionCommandsBase {
usage = "[id]", usage = "[id]",
desc = "Load a region as a WorldEdit selection", desc = "Load a region as a WorldEdit selection",
min = 0, max = 1) min = 0, max = 1)
public void select(CommandContext args, Actor sender) throws CommandException { public void select(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
LocalPlayer player = worldGuard.checkPlayer(sender); LocalPlayer player = worldGuard.checkPlayer(sender);
RegionManager manager = checkRegionManager(player.getWorld()); RegionManager manager = checkRegionManager(player.getWorld());
ProtectedRegion existing; ProtectedRegion existing;
@ -350,7 +350,8 @@ public final class RegionCommands extends RegionCommandsBase {
if (args.argsLength() == 0) { if (args.argsLength() == 0) {
existing = checkRegionStandingIn(manager, player, "/rg select %id%"); existing = checkRegionStandingIn(manager, player, "/rg select %id%");
} else { } else {
existing = checkExistingRegion(manager, args.getString(0), false); RegionIdentifier id = processRegionId(sender, args.getString(0), false);
existing = checkExistingRegion(sender, manager, id);
} }
// Check permissions // Check permissions
@ -374,7 +375,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "usw:", flags = "usw:",
desc = "Get information about a region", desc = "Get information about a region",
min = 0, max = 1) min = 0, max = 1)
public void info(CommandContext args, Actor sender) throws CommandException { public void info(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world World world = checkWorld(args, sender, 'w'); // Get the world
@ -392,7 +393,8 @@ public final class RegionCommands extends RegionCommandsBase {
existing = checkRegionStandingIn(manager, (LocalPlayer) sender, true, existing = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg info -w \"" + world.getName() + "\" %id%" + (args.hasFlag('u') ? " -u" : "") + (args.hasFlag('s') ? " -s" : "")); "/rg info -w \"" + world.getName() + "\" %id%" + (args.hasFlag('u') ? " -u" : "") + (args.hasFlag('s') ? " -s" : ""));
} else { // Get region from the ID } else { // Get region from the ID
existing = checkExistingRegion(manager, args.getString(0), true); RegionIdentifier id = processRegionId(sender, args.getString(0), true);
existing = checkExistingRegion(sender, manager, id);
} }
// Check permissions // Check permissions
@ -488,7 +490,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "g:w:eh:", flags = "g:w:eh:",
desc = "Set flags", desc = "Set flags",
min = 2) min = 2)
public void flag(CommandContext args, Actor sender) throws CommandException { public void flag(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world World world = checkWorld(args, sender, 'w'); // Get the world
@ -508,13 +510,13 @@ public final class RegionCommands extends RegionCommandsBase {
// Lookup the existing region // Lookup the existing region
RegionManager manager = checkRegionManager(world); RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(manager, args.getString(0), true); RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
// Check permissions // Check permissions
if (!permModel.maySetFlag(existing)) { if (!permModel.maySetFlag(existing)) {
throw new CommandPermissionsException(); throw new CommandPermissionsException();
} }
String regionId = existing.getId();
Flag<?> foundFlag = Flags.fuzzyMatchFlag(flagRegistry, flagName); Flag<?> foundFlag = Flags.fuzzyMatchFlag(flagRegistry, flagName);
@ -522,7 +524,7 @@ public final class RegionCommands extends RegionCommandsBase {
// can use, and do nothing afterwards // can use, and do nothing afterwards
if (foundFlag == null) { if (foundFlag == null) {
AsyncCommandBuilder.wrap(new FlagListBuilder(flagRegistry, permModel, existing, world, AsyncCommandBuilder.wrap(new FlagListBuilder(flagRegistry, permModel, existing, world,
regionId, sender, flagName), sender) id, sender, flagName), sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), "Flag list for invalid flag command.") .registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), "Flag list for invalid flag command.")
.onSuccess((Component) null, sender::print) .onSuccess((Component) null, sender::print)
.onFailure((Component) null, WorldGuard.getInstance().getExceptionConverter()) .onFailure((Component) null, WorldGuard.getInstance().getExceptionConverter())
@ -579,7 +581,8 @@ public final class RegionCommands extends RegionCommandsBase {
} }
if (!args.hasFlag('h')) { if (!args.hasFlag('h')) {
sender.print("Region flag " + foundFlag.getName() + " set on '" + regionId + "' to '" + value + "'."); String friendlyName = id.getDisplayName(sender);
sender.print("Region flag " + foundFlag.getName() + " set on '" + friendlyName + "' to '" + value + "'.");
} }
// No value? Clear the flag, if -g isn't specified // No value? Clear the flag, if -g isn't specified
@ -594,7 +597,8 @@ public final class RegionCommands extends RegionCommandsBase {
} }
if (!args.hasFlag('h')) { if (!args.hasFlag('h')) {
sender.print("Region flag " + foundFlag.getName() + " removed from '" + regionId + "'. (Any -g(roups) were also removed.)"); String friendlyName = id.getDisplayName(sender);
sender.print("Region flag " + foundFlag.getName() + " removed from '" + friendlyName + "'. (Any -g(roups) were also removed.)");
} }
} }
@ -630,7 +634,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "p:w:", flags = "p:w:",
desc = "View region flags", desc = "View region flags",
min = 0, max = 2) min = 0, max = 2)
public void flagHelper(CommandContext args, Actor sender) throws CommandException { public void flagHelper(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
World world = checkWorld(args, sender, 'w'); // Get the world World world = checkWorld(args, sender, 'w'); // Get the world
// Lookup the existing region // Lookup the existing region
@ -644,7 +648,8 @@ public final class RegionCommands extends RegionCommandsBase {
region = checkRegionStandingIn(manager, (LocalPlayer) sender, true, region = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg flags -w \"" + world.getName() + "\" %id%"); "/rg flags -w \"" + world.getName() + "\" %id%");
} else { // Get region from the ID } else { // Get region from the ID
region = checkExistingRegion(manager, args.getString(0), true); RegionIdentifier id = processRegionId(sender, args.getString(0), true);
region = checkExistingRegion(sender, manager, id);
} }
final RegionPermissionModel perms = getPermissionModel(sender); final RegionPermissionModel perms = getPermissionModel(sender);
@ -680,7 +685,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "w:", flags = "w:",
desc = "Set the priority of a region", desc = "Set the priority of a region",
min = 2, max = 2) min = 2, max = 2)
public void setPriority(CommandContext args, Actor sender) throws CommandException { public void setPriority(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world World world = checkWorld(args, sender, 'w'); // Get the world
@ -688,7 +693,8 @@ public final class RegionCommands extends RegionCommandsBase {
// Lookup the existing region // Lookup the existing region
RegionManager manager = checkRegionManager(world); RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(manager, args.getString(0), false); RegionIdentifier id = processRegionId(sender, args.getString(0), false);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
// Check permissions // Check permissions
if (!getPermissionModel(sender).maySetPriority(existing)) { if (!getPermissionModel(sender).maySetPriority(existing)) {
@ -697,7 +703,8 @@ public final class RegionCommands extends RegionCommandsBase {
existing.setPriority(priority); existing.setPriority(priority);
sender.print("Priority of '" + existing.getId() + "' set to " + priority + " (higher numbers override)."); String friendlyName = id.getDisplayName(sender);
sender.print("Priority of '" + friendlyName + "' set to " + priority + " (higher numbers override).");
} }
/** /**
@ -712,7 +719,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "w:", flags = "w:",
desc = "Set the parent of a region", desc = "Set the parent of a region",
min = 1, max = 2) min = 1, max = 2)
public void setParent(CommandContext args, Actor sender) throws CommandException { public void setParent(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world World world = checkWorld(args, sender, 'w'); // Get the world
@ -723,9 +730,11 @@ public final class RegionCommands extends RegionCommandsBase {
RegionManager manager = checkRegionManager(world); RegionManager manager = checkRegionManager(world);
// Get parent and child // Get parent and child
child = checkExistingRegion(manager, args.getString(0), false); RegionIdentifier childId = processRegionId(sender, args.getString(0), false);
child = checkExistingRegion(sender, manager, childId);
if (args.argsLength() == 2) { if (args.argsLength() == 2) {
parent = checkExistingRegion(manager, args.getString(1), false); RegionIdentifier parentId = processRegionId(sender, args.getString(1), false);
parent = checkExistingRegion(sender, manager, parentId);
} else { } else {
parent = null; parent = null;
} }
@ -739,11 +748,15 @@ public final class RegionCommands extends RegionCommandsBase {
child.setParent(parent); child.setParent(parent);
} catch (CircularInheritanceException e) { } catch (CircularInheritanceException e) {
// Tell the user what's wrong // Tell the user what's wrong
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), parent, null, sender);
assert parent != null; assert parent != null;
printout.append(ErrorFormat.wrap("Uh oh! Setting '", parent.getId(), "' to be the parent of '", child.getId(),
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,
"' would cause circular inheritance.")).newline(); "' would cause circular inheritance.")).newline();
printout.append(SubtleFormat.wrap("(Current inheritance on '", parent.getId(), "':")).newline(); printout.append(SubtleFormat.wrap("(Current inheritance on '", parentFriendlyName, "':")).newline();
printout.appendParentTree(true); printout.appendParentTree(true);
printout.append(SubtleFormat.wrap(")")); printout.append(SubtleFormat.wrap(")"));
printout.send(sender); printout.send(sender);
@ -751,8 +764,9 @@ public final class RegionCommands extends RegionCommandsBase {
} }
// Tell the user the current inheritance // Tell the user the current inheritance
String childFriendlyName = childId.getDisplayName(sender);
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), child, null, sender); RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), child, null, sender);
printout.append(TextComponent.of("Inheritance set for region '" + child.getId() + "'.", TextColor.LIGHT_PURPLE)); printout.append(TextComponent.of("Inheritance set for region '" + childFriendlyName + "'.", TextColor.LIGHT_PURPLE));
if (parent != null) { if (parent != null) {
printout.newline(); printout.newline();
printout.append(SubtleFormat.wrap("(Current inheritance:")).newline(); printout.append(SubtleFormat.wrap("(Current inheritance:")).newline();
@ -776,7 +790,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "fuw:", flags = "fuw:",
desc = "Remove a region", desc = "Remove a region",
min = 1, max = 1) min = 1, max = 1)
public void remove(CommandContext args, Actor sender) throws CommandException { public void remove(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender); warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world World world = checkWorld(args, sender, 'w'); // Get the world
@ -785,7 +799,8 @@ public final class RegionCommands extends RegionCommandsBase {
// Lookup the existing region // Lookup the existing region
RegionManager manager = checkRegionManager(world); RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(manager, args.getString(0), true); RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
// Check permissions // Check permissions
if (!getPermissionModel(sender).mayDelete(existing)) { if (!getPermissionModel(sender).mayDelete(existing)) {
@ -802,12 +817,15 @@ public final class RegionCommands extends RegionCommandsBase {
task.setRemovalStrategy(RemovalStrategy.UNSET_PARENT_IN_CHILDREN); task.setRemovalStrategy(RemovalStrategy.UNSET_PARENT_IN_CHILDREN);
} }
final String description = String.format("Removing region '%s' in '%s'", existing.getId(), world.getName()); String friendlyName = id.getDisplayName(sender);
final String description = String.format("Removing region '%s' in '%s'", friendlyName, world.getName());
AsyncCommandBuilder.wrap(task, sender) AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), description) .registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), description)
.sendMessageAfterDelay("Please wait... removing region.") .sendMessageAfterDelay("Please wait... removing region.")
.onSuccess((Component) null, removed -> sender.print(TextComponent.of( .onSuccess((Component) null, removed -> sender.print(TextComponent.of(
"Successfully removed " + removed.stream().map(ProtectedRegion::getId).collect(Collectors.joining(", ")) + ".", "Successfully removed " + removed.stream()
.map((r) -> r.getIdentifier().getDisplayName(sender))
.collect(Collectors.joining(", ")) + ".",
TextColor.LIGHT_PURPLE))) TextColor.LIGHT_PURPLE)))
.onFailure("Failed to remove region", WorldGuard.getInstance().getExceptionConverter()) .onFailure("Failed to remove region", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService()); .buildAndExec(WorldGuard.getInstance().getExecutorService());
@ -842,10 +860,6 @@ public final class RegionCommands extends RegionCommandsBase {
if (world != null) { if (world != null) {
RegionManager manager = checkRegionManager(world); 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()); final String description = String.format("Loading region data for '%s'.", world.getName());
AsyncCommandBuilder.wrap(new RegionManagerLoader(manager), sender) AsyncCommandBuilder.wrap(new RegionManagerLoader(manager), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description) .registerWithSupervisor(worldGuard.getSupervisor(), description)
@ -902,10 +916,6 @@ public final class RegionCommands extends RegionCommandsBase {
if (world != null) { if (world != null) {
RegionManager manager = checkRegionManager(world); 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()); final String description = String.format("Saving region data for '%s'.", world.getName());
AsyncCommandBuilder.wrap(new RegionManagerSaver(manager), sender) AsyncCommandBuilder.wrap(new RegionManagerSaver(manager), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description) .registerWithSupervisor(worldGuard.getSupervisor(), description)
@ -1068,14 +1078,15 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "sw:", flags = "sw:",
desc = "Teleports you to the location associated with the region.", desc = "Teleports you to the location associated with the region.",
min = 1, max = 1) min = 1, max = 1)
public void teleport(CommandContext args, Actor sender) throws CommandException { public void teleport(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
LocalPlayer player = worldGuard.checkPlayer(sender); LocalPlayer player = worldGuard.checkPlayer(sender);
Location teleportLocation; Location teleportLocation;
// Lookup the existing region // Lookup the existing region
World world = checkWorld(args, player, 'w'); World world = checkWorld(args, player, 'w');
RegionManager regionManager = checkRegionManager(world); RegionManager regionManager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(regionManager, args.getString(0), true); RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion existing = checkExistingRegion(sender, regionManager, id);
// Check permissions // Check permissions
if (!getPermissionModel(player).mayTeleportTo(existing)) { if (!getPermissionModel(player).mayTeleportTo(existing)) {
@ -1098,9 +1109,10 @@ public final class RegionCommands extends RegionCommandsBase {
} }
} }
String friendlyName = id.getDisplayName(sender);
player.teleport(teleportLocation, player.teleport(teleportLocation,
"Teleported you to the region '" + existing.getId() + "'.", "Teleported you to the region '" + friendlyName + "'.",
"Unable to teleport to region '" + existing.getId() + "'."); "Unable to teleport to region '" + friendlyName + "'.");
} }
@Command(aliases = {"toggle-bypass", "bypass"}, @Command(aliases = {"toggle-bypass", "bypass"},
@ -1123,12 +1135,12 @@ public final class RegionCommands extends RegionCommandsBase {
private final RegionPermissionModel permModel; private final RegionPermissionModel permModel;
private final ProtectedRegion existing; private final ProtectedRegion existing;
private final World world; private final World world;
private final String regionId; private final RegionIdentifier regionId;
private final Actor sender; private final Actor sender;
private final String flagName; private final String flagName;
FlagListBuilder(FlagRegistry flagRegistry, RegionPermissionModel permModel, ProtectedRegion existing, FlagListBuilder(FlagRegistry flagRegistry, RegionPermissionModel permModel, ProtectedRegion existing,
World world, String regionId, Actor sender, String flagName) { World world, RegionIdentifier regionId, Actor sender, String flagName) {
this.flagRegistry = flagRegistry; this.flagRegistry = flagRegistry;
this.permModel = permModel; this.permModel = permModel;
this.existing = existing; this.existing = existing;
@ -1160,9 +1172,10 @@ public final class RegionCommands extends RegionCommandsBase {
for (int i = 0; i < flagList.size(); i++) { for (int i = 0; i < flagList.size(); i++) {
String flag = flagList.get(i); String flag = flagList.get(i);
String qualifiedName = regionId.getQualifiedName();
builder.append(TextComponent.of(flag, i % 2 == 0 ? TextColor.GRAY : TextColor.WHITE) builder.append(TextComponent.of(flag, i % 2 == 0 ? TextColor.GRAY : TextColor.WHITE)
.hoverEvent(clickToSet).clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, .hoverEvent(clickToSet).clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg flag -w \"" + world.getName() + "\" " + regionId + " " + flag + " "))); "/rg flag -w \"" + world.getName() + "\" " + qualifiedName + " " + flag + " ")));
if (i < flagList.size() + 1) { if (i < flagList.size() + 1) {
builder.append(TextComponent.of(", ")); builder.append(TextComponent.of(", "));
} }
@ -1172,10 +1185,12 @@ public final class RegionCommands extends RegionCommandsBase {
.append(TextComponent.newline()) .append(TextComponent.newline())
.append(builder.build()); .append(builder.build());
if (sender.isPlayer()) { if (sender.isPlayer()) {
String friendlyName = regionId.getDisplayName(sender);
String qualifiedName = regionId.getQualifiedName();
return ret.append(TextComponent.of("Or use the command ", TextColor.LIGHT_PURPLE) return ret.append(TextComponent.of("Or use the command ", TextColor.LIGHT_PURPLE)
.append(TextComponent.of("/rg flags " + regionId, TextColor.AQUA) .append(TextComponent.of("/rg flags " + friendlyName, TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg flags -w \"" + world.getName() + "\" " + regionId)))); "/rg flags -w \"" + world.getName() + "\" " + qualifiedName))));
} }
return ret; return ret;
} }

View File

@ -33,13 +33,13 @@ import com.sk89q.worldedit.regions.Polygonal2DRegion;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector; 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.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.text.TextComponent; 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.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; 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.TextColor;
import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard; 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.FlagContext;
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat; import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion; import com.sk89q.worldguard.protection.regions.*;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; import com.sk89q.worldguard.util.profile.Profile;
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.Set;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
class RegionCommandsBase { class RegionCommandsBase {
@ -77,9 +77,9 @@ class RegionCommandsBase {
* Gets the world from the given flag, or falling back to the the current player * 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. * if the sender is a player, otherwise reporting an error.
* *
* @param args the arguments * @param args the arguments
* @param sender the sender * @param sender the sender
* @param flag the flag (such as 'w') * @param flag the flag (such as 'w')
* @return a world * @return a world
* @throws CommandException on error * @throws CommandException on error
*/ */
@ -95,28 +95,190 @@ 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. * Validate a region ID.
* *
* @param id the id * @param id the id
* @param allowGlobal whether __global__ is allowed * @param allowGlobal whether __global__ is allowed
* @return the id given * @return the id given
* @throws CommandException thrown on an error * @throws CommandException thrown on an error
*/ */
@Deprecated
protected static String checkRegionId(String id, boolean allowGlobal) throws CommandException { protected static String checkRegionId(String id, boolean allowGlobal) throws CommandException {
if (!ProtectedRegion.isValidId(id)) { checkName(id, allowGlobal);
throw new CommandException(
"The region name of '" + id + "' contains characters that are not allowed.");
}
if (!allowGlobal && id.equalsIgnoreCase("__global__")) { // Sorry, no global
throw new CommandException(
"Sorry, you can't use __global__ here.");
}
return id; 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)) {
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;
}
int unqualifiedNameStartIndex = namespaceSeparatorIndex + 1;
if (unqualifiedNameStartIndex == id.length()) {
return "";
}
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);
}
/** /**
* Get a protected region by a given name, otherwise throw a * Get a protected region by a given name, otherwise throw a
* {@link CommandException}. * {@link CommandException}.
@ -128,6 +290,7 @@ class RegionCommandsBase {
* @param allowGlobal true to allow selecting __global__ * @param allowGlobal true to allow selecting __global__
* @throws CommandException thrown if no region is found by the given name * @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 { protected static ProtectedRegion checkExistingRegion(RegionManager regionManager, String id, boolean allowGlobal) throws CommandException {
// Validate the id // Validate the id
checkRegionId(id, allowGlobal); checkRegionId(id, allowGlobal);
@ -150,6 +313,36 @@ class RegionCommandsBase {
return region; 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. * Get the region at the player's location, if possible.
@ -204,10 +397,12 @@ class RegionCommandsBase {
builder.append(TextComponent.of(", ")); builder.append(TextComponent.of(", "));
} }
first = false; first = false;
TextComponent regionComp = TextComponent.of(region.getId(), TextColor.AQUA);
RegionIdentifier id = region.getIdentifier();
TextComponent regionComp = TextComponent.of(id.getDisplayName(player), TextColor.AQUA);
if (rgCmd != null && rgCmd.contains("%id%")) { if (rgCmd != null && rgCmd.contains("%id%")) {
regionComp = regionComp.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to pick this region"))) 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%", region.getId()))); .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, rgCmd.replace("%id%", id.getQualifiedName())));
} }
builder.append(regionComp); builder.append(regionComp);
} }
@ -244,10 +439,23 @@ class RegionCommandsBase {
* @param id the ID * @param id the ID
* @throws CommandException thrown if the ID already exists * @throws CommandException thrown if the ID already exists
*/ */
@Deprecated
protected static void checkRegionDoesNotExist(RegionManager manager, String id, boolean mayRedefine) throws CommandException { 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)) { if (manager.hasRegion(id)) {
throw new CommandException("A region with that name already exists. Please choose another name." + throw new CommandException("A region with that name already exists. Please choose another name." +
(mayRedefine ? " To change the shape, use /region redefine " + id + "." : "")); (mayRedefine ? " To change the shape, use /region redefine " + id.getDisplayName(actor) + "." : ""));
} }
} }
@ -280,7 +488,20 @@ class RegionCommandsBase {
* @return a new region * @return a new region
* @throws CommandException thrown on an error * @throws CommandException thrown on an error
*/ */
@Deprecated
protected static ProtectedRegion checkRegionFromSelection(LocalPlayer player, String id) throws CommandException { 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); Region selection = checkSelection(player);
// Detect the type of region from WorldEdit // Detect the type of region from WorldEdit

View File

@ -19,6 +19,7 @@
package com.sk89q.worldguard.commands.region; package com.sk89q.worldguard.commands.region;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import com.sk89q.worldguard.util.profile.cache.ProfileCache; import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
@ -58,6 +59,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
@Nullable @Nullable
private final ProfileCache cache; private final ProfileCache cache;
private final TextComponentProducer builder = new TextComponentProducer(); private final TextComponentProducer builder = new TextComponentProducer();
private final Actor actor;
private final RegionPermissionModel perms; private final RegionPermissionModel perms;
/** /**
@ -70,6 +72,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
this.world = world; this.world = world;
this.region = region; this.region = region;
this.cache = cache; this.cache = cache;
this.actor = actor;
this.perms = actor != null && actor.isPlayer() ? new RegionPermissionModel(actor) : null; this.perms = actor != null && actor.isPlayer() ? new RegionPermissionModel(actor) : null;
} }
@ -85,8 +88,10 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
*/ */
public void appendBasics() { public void appendBasics() {
builder.append(TextComponent.of("Region: ", TextColor.BLUE)); builder.append(TextComponent.of("Region: ", TextColor.BLUE));
builder.append(TextComponent.of(region.getId(), TextColor.YELLOW)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg info -w \"" + world + "\" " + region.getId()))); 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(" (type=", TextColor.GRAY)); builder.append(TextComponent.of(" (type=", TextColor.GRAY));
builder.append(TextComponent.of(region.getType().getName())); builder.append(TextComponent.of(region.getType().getName()));

View File

@ -76,6 +76,7 @@ public abstract class ConfigurationManager {
public boolean migrateRegionsToUuid; public boolean migrateRegionsToUuid;
public boolean keepUnresolvedNames; public boolean keepUnresolvedNames;
public boolean particleEffects; public boolean particleEffects;
public boolean useNamespaces;
@Unreported public Map<String, String> hostKeys = new HashMap<>(); @Unreported public Map<String, String> hostKeys = new HashMap<>();
public boolean hostKeysAllowFMLClients; public boolean hostKeysAllowFMLClients;

View File

@ -63,6 +63,7 @@ public abstract class YamlConfigurationManager extends ConfigurationManager {
usePlayerMove = config.getBoolean("use-player-move-event", true); usePlayerMove = config.getBoolean("use-player-move-event", true);
usePlayerTeleports = config.getBoolean("use-player-teleports", true); usePlayerTeleports = config.getBoolean("use-player-teleports", true);
particleEffects = config.getBoolean("use-particle-effects", true); particleEffects = config.getBoolean("use-particle-effects", true);
useNamespaces = config.getBoolean("use-namespaces", true);
deopOnJoin = config.getBoolean("security.deop-everyone-on-join", false); deopOnJoin = config.getBoolean("security.deop-everyone-on-join", false);
blockInGameOp = config.getBoolean("security.block-in-game-op-command", false); blockInGameOp = config.getBoolean("security.block-in-game-op-command", false);

View File

@ -26,6 +26,7 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.flags.Flag; import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import javax.annotation.Nullable; import javax.annotation.Nullable;

View File

@ -34,6 +34,7 @@ import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase; import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.StorageException; import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedRegion; 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.protection.util.RegionCollectionConsumer;
import com.sk89q.worldguard.util.Normal; import com.sk89q.worldguard.util.Normal;
@ -242,10 +243,22 @@ public final class RegionManager {
* @param id the name of the region * @param id the name of the region
* @return true if this index contains the region * @return true if this index contains the region
*/ */
@Deprecated
public boolean hasRegion(String id) { public boolean hasRegion(String id) {
return index.contains(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 * Get the region named by the given name (equality determined using
* {@link Normal}). * {@link Normal}).
@ -254,11 +267,24 @@ public final class RegionManager {
* @return a region or {@code null} * @return a region or {@code null}
*/ */
@Nullable @Nullable
@Deprecated
public ProtectedRegion getRegion(String id) { public ProtectedRegion getRegion(String id) {
checkNotNull(id); checkNotNull(id);
return index.get(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} * @deprecated Use exact ids with {@link #getRegion}
*/ */

View File

@ -70,12 +70,13 @@ public class HashMapIndex extends AbstractRegionIndex implements ConcurrentRegio
region.setDirty(true); region.setDirty(true);
synchronized (lock) { synchronized (lock) {
String normalId = normalize(region.getId()); String newFullId = region.getIdentifier().getLegacyQualifiedName();
String normalId = normalize(newFullId);
ProtectedRegion existing = regions.get(normalId); ProtectedRegion existing = regions.get(normalId);
// Casing / form of ID has changed // Casing / form of ID has changed
if (existing != null && !existing.getId().equals(region.getId())) { if (existing != null && !existing.getIdentifier().getLegacyQualifiedName().equals(newFullId)) {
removed.add(existing); removed.add(existing);
} }

View File

@ -0,0 +1,60 @@
/*
* 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;
}
}
}

View File

@ -0,0 +1,34 @@
/*
* 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));
}
}
}
}

View File

@ -0,0 +1,59 @@
/*
* 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>";
}
}
}

View File

@ -0,0 +1,34 @@
/*
* 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);
}

View File

@ -0,0 +1,114 @@
/*
* 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());
}
}

View File

@ -0,0 +1,120 @@
/*
* 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());
}
}

View File

@ -19,56 +19,32 @@
package com.sk89q.worldguard.protection.managers.storage.file; 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.YAMLFormat;
import com.sk89q.util.yaml.YAMLNode; import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.util.yaml.YAMLProcessor; import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldedit.math.BlockVector2; 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.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.FlagUtil; import com.sk89q.worldguard.protection.flags.FlagUtil;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry; import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionDifference; import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException; import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase; 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.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion; import com.sk89q.worldguard.protection.regions.*;
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.parser.ParserException;
import org.yaml.snakeyaml.representer.Representer;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.HashMap; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.HashSet; import static com.sk89q.worldguard.protection.managers.storage.file.YamlCommon.YAML_GLOBAL_NAMESPACE_NAME;
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. * A store that persists regions in a YAML-encoded file.
*/ */
public class YamlRegionFile implements RegionDatabase { 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" + private static final String FILE_HEADER = "#\r\n" +
"# WorldGuard regions file\r\n" + "# WorldGuard regions file\r\n" +
"#\r\n" + "#\r\n" +
@ -81,17 +57,19 @@ public class YamlRegionFile implements RegionDatabase {
"# REMEMBER TO KEEP PERIODICAL BACKUPS.\r\n" + "# REMEMBER TO KEEP PERIODICAL BACKUPS.\r\n" +
"#"; "#";
private final String name; private static final List<YamlReader> YAML_READERS = new ArrayList<>();
private final File file;
static { static {
DumperOptions options = new DumperOptions(); // IMPORTANT: For best performance, add these in reverse order.
options.setIndent(4); // We always want the latest version to be attempted first, so that once migrated, we are checking
options.setDefaultFlowStyle(FlowStyle.AUTO); // one version, not n.
YAML_READERS.add(new YamlReaderVersionTwo());
ERROR_DUMP_YAML = new Yaml(new SafeConstructor(), new Representer(), options); YAML_READERS.add(new YamlReaderVersionOne());
} }
private final String name;
private final File file;
/** /**
* Create a new instance. * Create a new instance.
* *
@ -112,80 +90,22 @@ public class YamlRegionFile implements RegionDatabase {
@Override @Override
public Set<ProtectedRegion> loadAll(FlagRegistry flagRegistry) throws StorageException { public Set<ProtectedRegion> loadAll(FlagRegistry flagRegistry) throws StorageException {
Map<String, ProtectedRegion> loaded = new HashMap<>();
YAMLProcessor config = createYamlProcessor(file); YAMLProcessor config = createYamlProcessor(file);
try { try {
config.load(); config.load();
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
return new HashSet<>(loaded.values()); return new HashSet<>();
} catch (IOException | ParserException e) { } catch (IOException | ParserException e) {
throw new StorageException("Failed to load region data from '" + file + "'", e); throw new StorageException("Failed to load region data from '" + file + "'", e);
} }
Map<String, YAMLNode> regionData = config.getNodes("regions"); for (YamlReader reader : YAML_READERS) {
if (reader.canLoad(config)) {
if (regionData == null) { return reader.load(flagRegistry, config);
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);
} }
} }
// Relink parents throw new IllegalStateException("No YAML reader was registered that understands the saved region information");
RegionDatabaseUtils.relinkParents(loaded, parentSets);
return new HashSet<>(loaded.values());
} }
@Override @Override
@ -197,13 +117,25 @@ public class YamlRegionFile implements RegionDatabase {
config.clear(); config.clear();
config.setProperty("version", YAML_READERS.get(0).getVersion());
YAMLNode regionsNode = config.addNode("regions"); YAMLNode regionsNode = config.addNode("regions");
Map<String, Object> map = regionsNode.getMap();
// Creates a mapping of existing namespace node names, to their underlying YAMLNode.
Map<String, YAMLNode> namespaceMap = new HashMap<>();
for (ProtectedRegion region : regions) { for (ProtectedRegion region : regions) {
Map<String, Object> nodeMap = new HashMap<>(); RegionIdentifier identifier = region.getIdentifier();
map.put(region.getId(), nodeMap);
YAMLNode node = new YAMLNode(nodeMap, false); 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());
if (region instanceof ProtectedCuboidRegion) { if (region instanceof ProtectedCuboidRegion) {
ProtectedCuboidRegion cuboid = (ProtectedCuboidRegion) region; ProtectedCuboidRegion cuboid = (ProtectedCuboidRegion) region;
@ -238,7 +170,7 @@ public class YamlRegionFile implements RegionDatabase {
ProtectedRegion parent = region.getParent(); ProtectedRegion parent = region.getParent();
if (parent != null) { if (parent != null) {
node.setProperty("parent", parent.getId()); node.setProperty("parent", parent.getIdentifier().getLegacyQualifiedName());
} }
} }
@ -257,46 +189,10 @@ public class YamlRegionFile implements RegionDatabase {
throw new DifferenceSaveException("Not supported"); 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) { private Map<String, Object> getFlagData(ProtectedRegion region) {
return FlagUtil.marshal(region.getFlags()); 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) { private Map<String, Object> getDomainData(DefaultDomain domain) {
Map<String, Object> domainData = new HashMap<>(); Map<String, Object> domainData = new HashMap<>();
@ -331,19 +227,4 @@ public class YamlRegionFile implements RegionDatabase {
checkNotNull(file); checkNotNull(file);
return new YAMLProcessor(file, false, YAMLFormat.COMPACT); 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>";
}
}
} }

View File

@ -44,6 +44,7 @@ public class GlobalProtectedRegion extends ProtectedRegion {
* *
* @param id the ID * @param id the ID
*/ */
@Deprecated
public GlobalProtectedRegion(String id) { public GlobalProtectedRegion(String id) {
this(id, false); this(id, false);
} }
@ -54,7 +55,29 @@ public class GlobalProtectedRegion extends ProtectedRegion {
* @param id the ID * @param id the ID
* @param transientRegion whether this region should only be kept in memory and not be saved * @param transientRegion whether this region should only be kept in memory and not be saved
*/ */
@Deprecated
public GlobalProtectedRegion(String id, boolean transientRegion) { 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); super(id, transientRegion);
min = BlockVector3.ZERO; min = BlockVector3.ZERO;
max = BlockVector3.ZERO; max = BlockVector3.ZERO;

View File

@ -47,6 +47,7 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
* @param pt1 the first point of this region * @param pt1 the first point of this region
* @param pt2 the second point of this region * @param pt2 the second point of this region
*/ */
@Deprecated
public ProtectedCuboidRegion(String id, BlockVector3 pt1, BlockVector3 pt2) { public ProtectedCuboidRegion(String id, BlockVector3 pt1, BlockVector3 pt2) {
this(id, false, pt1, pt2); this(id, false, pt1, pt2);
} }
@ -59,7 +60,34 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
* @param pt1 the first point of this region * @param pt1 the first point of this region
* @param pt2 the second point of this region * @param pt2 the second point of this region
*/ */
@Deprecated
public ProtectedCuboidRegion(String id, boolean transientRegion, BlockVector3 pt1, BlockVector3 pt2) { 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); super(id, transientRegion);
setMinMaxPoints(pt1, pt2); setMinMaxPoints(pt1, pt2);
} }

View File

@ -47,6 +47,7 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
* @param minY the minimum y coordinate * @param minY the minimum y coordinate
* @param maxY the maximum y coordinate * @param maxY the maximum y coordinate
*/ */
@Deprecated
public ProtectedPolygonalRegion(String id, List<BlockVector2> points, int minY, int maxY) { public ProtectedPolygonalRegion(String id, List<BlockVector2> points, int minY, int maxY) {
this(id, false, points, minY, maxY); this(id, false, points, minY, maxY);
} }
@ -60,7 +61,37 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
* @param minY the minimum y coordinate * @param minY the minimum y coordinate
* @param maxY the maximum y coordinate * @param maxY the maximum y coordinate
*/ */
@Deprecated
public ProtectedPolygonalRegion(String id, boolean transientRegion, List<BlockVector2> points, int minY, int maxY) { 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); super(id, transientRegion);
ImmutableList<BlockVector2> immutablePoints = ImmutableList.copyOf(points); ImmutableList<BlockVector2> immutablePoints = ImmutableList.copyOf(points);
setMinMaxPoints(immutablePoints, minY, maxY); setMinMaxPoints(immutablePoints, minY, maxY);

View File

@ -28,7 +28,6 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.domains.DefaultDomain; import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.Flag; import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.util.ChangeTracked; import com.sk89q.worldguard.util.ChangeTracked;
import com.sk89q.worldguard.util.Normal;
import java.awt.geom.Area; import java.awt.geom.Area;
import java.awt.geom.Line2D; import java.awt.geom.Line2D;
@ -37,7 +36,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -50,12 +48,11 @@ import javax.annotation.Nullable;
public abstract class ProtectedRegion implements ChangeTracked, Comparable<ProtectedRegion> { public abstract class ProtectedRegion implements ChangeTracked, Comparable<ProtectedRegion> {
public static final String GLOBAL_REGION = "__global__"; 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 min;
protected BlockVector3 max; protected BlockVector3 max;
private final String id; private final RegionIdentifier id;
private final boolean transientRegion; private final boolean transientRegion;
private int priority = 0; private int priority = 0;
private ProtectedRegion parent; private ProtectedRegion parent;
@ -67,18 +64,13 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
/** /**
* Construct a new instance of this region. * Construct a new instance of this region.
* *
* @param id the name of this region * @param id the name information for this region
* @param transientRegion whether this region should only be kept in memory and not be saved * @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(String id, boolean transientRegion) { // Package private because we can't have people creating their own region types ProtectedRegion(RegionIdentifier id, boolean transientRegion) { // Package private because we can't have people creating their own region types
checkNotNull(id); checkNotNull(id);
if (!isValidId(id)) { this.id = id;
throw new IllegalArgumentException("Invalid region ID: " + id);
}
this.id = Normal.normalize(id);
this.transientRegion = transientRegion; this.transientRegion = transientRegion;
} }
@ -119,7 +111,17 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
* *
* @return the name * @return the name
*/ */
@Deprecated
public String getId() { public String getId() {
return id.getLegacyQualifiedName();
}
/**
* Gets the identifier info for this region.
*
* @return the identifier info
*/
public RegionIdentifier getIdentifier() {
return id; return id;
} }
@ -734,9 +736,9 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
* @param id the id to check * @param id the id to check
* @return whether the region id given is valid * @return whether the region id given is valid
*/ */
@Deprecated
public static boolean isValidId(String id) { public static boolean isValidId(String id) {
checkNotNull(id); return RegionIdentifier.isValidName(id);
return VALID_ID_PATTERN.matcher(id).matches();
} }
/** /**

View File

@ -0,0 +1,147 @@
/*
* 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();
}
}

View File

@ -64,6 +64,11 @@ public class TestPlayer extends AbstractPlayerActor implements LocalPlayer {
return uuid; return uuid;
} }
@Override
public String getDefaultNamespace() {
return null;
}
@Override @Override
public boolean hasGroup(String group) { public boolean hasGroup(String group) {
return groups.contains(group.toLowerCase()); return groups.contains(group.toLowerCase());