Compare commits

...
Author SHA1 Message Date
Wyatt Childers ca7967085b Implement region namespaces 2020-01-19 14:10:33 -05:00
wizjany b835ee39d5 Check water/lava placement from dispensers on edge of region.
Fixes WORLDGUARD-4161.
2020-01-03 23:11:56 -05:00
Pieter12345 4a7552e6be Prevent pushing pistons across region borders
Pistons are classified as not pushable regardless of their state, causing WorldGuard to not protect against them moving. This commit fixes that.
2020-01-01 13:53:09 -05:00
Joo200 c6c0fc9d74 Fixed failed checkstyle gradle task 2020-01-01 13:53:01 -05:00
wizjany f43a4eaad8 Add spawn-protection overlap check when defining regions.
Update cached username on login.
Bump WorldEdit dep version.
2019-12-19 15:42:34 -05:00
JOO200 abfa5cb6a5 bee nests can be modified by right click (like beehives) 2019-12-16 14:08:04 -05:00
JOO200 05f7d68705 Use Paper-API 1.15 as Dependency 2019-12-16 14:08:04 -05:00
wizjany 9adac4f239 Initial 1.15 stuff.
Materials is not really cross-version compatible. Really could do with
some rewriting at some point.
2019-12-10 23:48:50 -05:00
wizjany c5355adb4b Back to snapshot. 2019-11-22 23:51:25 -05:00
34 changed files with 1236 additions and 292 deletions

No files matched your search

+1
View File
@@ -1,6 +1,7 @@
object Versions {
// const val PISTON = "0.4.3"
// const val AUTO_VALUE = "1.6.5"
const val WORLDEDIT = "7.1.0-SNAPSHOT"
const val JUNIT = "4.11"
const val SQUIRRELID = "0.2.0"
}
+4 -2
View File
@@ -7,9 +7,11 @@
<module name="FileTabCharacter"/>
<module name="SuppressionFilter">
<property name="file" value="${basedir}/config/checkstyle/suppressions.xml"/>
<property name="file" value="${config_loc}/suppressions.xml"/>
</module>
<module name="TreeWalker">
<!-- Important basics -->
<!-- <module name="PackageDeclaration"/> Unlikely that we would miss this in a PR -->
@@ -20,7 +22,7 @@
It is a bit draconian, so update as necessary!
-->
<module name="ImportControl">
<property name="file" value="${basedir}/config/checkstyle/import-control.xml"/>
<property name="file" value="${config_loc}/import-control.xml"/>
</module>
<!-- Code -->
+1 -1
View File
@@ -1,2 +1,2 @@
group=com.sk89q.worldguard
version=7.0.1
version=7.0.2-SNAPSHOT
+2 -2
View File
@@ -24,9 +24,9 @@ repositories {
dependencies {
"compile"(project(":worldguard-core"))
//"compile"(project(":worldguard-libs:bukkit"))
"api"("com.destroystokyo.paper:paper-api:1.14.4-R0.1-SNAPSHOT")
"api"("com.destroystokyo.paper:paper-api:1.15-R0.1-SNAPSHOT")
"implementation"("io.papermc:paperlib:1.0.2")
"api"("com.sk89q.worldedit:worldedit-bukkit:7.0.1-SNAPSHOT") { isTransitive = false }
"api"("com.sk89q.worldedit:worldedit-bukkit:${Versions.WORLDEDIT}") { isTransitive = false }
"implementation"("com.sk89q:commandbook:2.3") { isTransitive = false }
"implementation"("org.bstats:bstats-bukkit:1.5")
}
@@ -24,6 +24,7 @@ import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.weather.WeatherTypes;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import io.papermc.lib.PaperLib;
import org.bukkit.BanList.Type;
import org.bukkit.Bukkit;
@@ -54,6 +55,16 @@ public class BukkitPlayer extends com.sk89q.worldedit.bukkit.BukkitPlayer implem
return name;
}
@Override
public String getDefaultNamespace() {
// TODO: Add a per player override
boolean useNamespaces = WorldGuard.getInstance().getPlatform().getGlobalStateManager().useNamespaces;
if (useNamespaces) {
return getUniqueId().toString();
}
return null;
}
@Override
public boolean hasGroup(String group) {
return plugin.inGroup(getPlayer(), group);
@@ -19,12 +19,18 @@
package com.sk89q.worldguard.bukkit;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.report.ReportList;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.util.profile.resolver.PaperProfileService;
import com.sk89q.worldguard.bukkit.protection.events.flags.FlagContextCreateEvent;
import com.sk89q.worldguard.bukkit.session.BukkitSessionManager;
@@ -52,6 +58,7 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.permissions.Permissible;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -251,4 +258,22 @@ public class BukkitWorldGuardPlatform implements WorldGuardPlatform {
return new CacheForwardingService(new CombinedProfileService(services),
profileCache);
}
@Nullable
@Override
public ProtectedRegion getSpawnProtection(World world) {
if (world instanceof BukkitWorld) {
org.bukkit.World bWorld = ((BukkitWorld) world).getWorld();
if (bWorld.getUID().equals(Bukkit.getServer().getWorlds().get(0).getUID())) {
int radius = Bukkit.getServer().getSpawnRadius();
if (radius > 0) {
BlockVector3 spawnLoc = BukkitAdapter.asBlockVector(bWorld.getSpawnLocation());
return new ProtectedCuboidRegion("__spawn_protection__",
spawnLoc.subtract(radius, 0, radius).withY(world.getMinimumPoint().getY()),
spawnLoc.add(radius, 0, radius).withY(world.getMaxY()));
}
}
}
return null;
}
}
@@ -357,7 +357,8 @@ public class EventAbstractionListener extends AbstractListener {
for (int i = 0; i < blocks.size(); i++) {
Block existing = blocks.get(i);
if (existing.getPistonMoveReaction() == PistonMoveReaction.MOVE
|| existing.getPistonMoveReaction() == PistonMoveReaction.PUSH_ONLY) {
|| existing.getPistonMoveReaction() == PistonMoveReaction.PUSH_ONLY
|| existing.getType() == Material.PISTON || existing.getType() == Material.STICKY_PISTON) {
blocks.set(i, existing.getRelative(dir));
}
}
@@ -1067,6 +1068,13 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), Materials.getEntitySpawnEgg(item.getType())));
return;
}
// handle water/lava placement
if (item != null && (item.getType() == Material.WATER_BUCKET || item.getType() == Material.LAVA_BUCKET)) {
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, placed.getLocation(),
item.getType() == Material.WATER_BUCKET ? Material.WATER : Material.LAVA));
return;
}
}
private static <T extends Event & Cancellable> void handleInventoryHolderUse(T originalEvent, Cause cause, InventoryHolder holder) {
@@ -24,13 +24,14 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.BukkitPlayer;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent;
import com.sk89q.worldguard.session.AbstractSessionManager;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.util.profile.Profile;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import java.util.Collection;
@@ -57,10 +58,12 @@ public class BukkitSessionManager extends AbstractSessionManager implements Runn
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
public void onPlayerProcess(ProcessPlayerEvent event) {
// Pre-load a session
LocalPlayer player = WorldGuardPlugin.inst().wrapPlayer(event.getPlayer());
get(player).initialize(player);
WorldGuard.getInstance().getExecutorService().submit(() ->
WorldGuard.getInstance().getProfileCache().put(new Profile(player.getUniqueId(), player.getName())));
}
@Override
@@ -75,7 +78,7 @@ public class BukkitSessionManager extends AbstractSessionManager implements Runn
public boolean hasBypass(LocalPlayer player, World world) {
if (player instanceof BukkitPlayer) {
if (((BukkitPlayer) player).getPlayer().hasMetadata("NPC")
&& WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(world).fakePlayerBuildOverride)
&& WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(world).fakePlayerBuildOverride)
return true;
}
return super.hasBypass(player, world);
@@ -692,6 +692,16 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.SUSPICIOUS_STEW, 0);
MATERIAL_FLAGS.put(Material.SWEET_BERRIES, 0);
// 1.15
try {
MATERIAL_FLAGS.put(Material.BEEHIVE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BEE_NEST, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.HONEY_BLOCK, 0);
MATERIAL_FLAGS.put(Material.HONEYCOMB_BLOCK, 0);
MATERIAL_FLAGS.put(Material.HONEY_BOTTLE, 0);
MATERIAL_FLAGS.put(Material.HONEYCOMB, 0);
} catch (NoSuchFieldError ignored) {
}
// Fake tags
for (Material m : shulkerBoxes) {
@@ -998,6 +1008,7 @@ public final class Materials {
switch (material) {
case SPIDER_SPAWN_EGG:
case BAT_SPAWN_EGG:
case BEE_SPAWN_EGG:
case BLAZE_SPAWN_EGG:
case CAT_SPAWN_EGG:
case CAVE_SPIDER_SPAWN_EGG:
@@ -1066,6 +1077,8 @@ public final class Materials {
return EntityType.SPIDER;
case BAT_SPAWN_EGG:
return EntityType.BAT;
case BEE_SPAWN_EGG:
return EntityType.BEE;
case BLAZE_SPAWN_EGG:
return EntityType.BLAZE;
case CAT_SPAWN_EGG:
+1 -1
View File
@@ -8,7 +8,7 @@ applyPlatformAndCoreConfiguration()
dependencies {
"compile"(project(":worldguard-libs:core"))
"compile"("com.sk89q.worldedit:worldedit-core:7.0.1-SNAPSHOT")
"compile"("com.sk89q.worldedit:worldedit-core:${Versions.WORLDEDIT}")
"implementation"("org.flywaydb:flyway-core:3.0")
"compileOnly"("com.google.code.findbugs:jsr305:1.3.9")
@@ -31,6 +31,29 @@ import java.util.List;
public interface LocalPlayer extends Player, RegionAssociable {
/**
* Returns the default namespace for this player.
*
* @return the default namespace.
*/
String getDefaultNamespace();
default boolean isDefaultNamespace(String otherNamespace) {
String namespace = getDefaultNamespace();
// If both are null, they're the same (the global)
if (namespace == null && otherNamespace == null) {
return true;
}
// If only one is null, they're a mismatch
if (namespace == null || otherNamespace == null) {
return false;
}
// Compare string equality
return namespace.equalsIgnoreCase(otherNamespace);
}
/**
* Returns true if this player is inside a group.
*
@@ -32,6 +32,7 @@ import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import com.sk89q.worldguard.protection.util.DomainInputResolver;
import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy;
@@ -50,13 +51,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "nw:",
desc = "Add a member to a region",
min = 2)
public void addMember(CommandContext args, Actor sender) throws CommandException {
public void addMember(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
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
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);
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)
.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())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -82,15 +84,14 @@ public class MemberCommands extends RegionCommandsBase {
flags = "nw:",
desc = "Add an owner to a region",
min = 2)
public void addOwner(CommandContext args, Actor sender) throws CommandException {
public void addOwner(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
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
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);
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)
.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())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -149,13 +151,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "naw:",
desc = "Remove an owner to a region",
min = 1)
public void removeMember(CommandContext args, Actor sender) throws CommandException {
public void removeMember(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
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
if (!getPermissionModel(sender).mayRemoveMembers(region)) {
@@ -178,11 +180,12 @@ public class MemberCommands extends RegionCommandsBase {
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)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.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())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -192,13 +195,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "naw:",
desc = "Remove an owner to a region",
min = 1)
public void removeOwner(CommandContext args, Actor sender) throws CommandException {
public void removeOwner(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
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
if (!getPermissionModel(sender).mayRemoveOwners(region)) {
@@ -221,11 +224,12 @@ public class MemberCommands extends RegionCommandsBase {
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)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.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())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -32,6 +32,7 @@ import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.LabelFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
@@ -44,7 +45,6 @@ import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.commands.CommandUtils;
import com.sk89q.worldguard.commands.task.RegionAdder;
import com.sk89q.worldguard.commands.task.RegionLister;
import com.sk89q.worldguard.commands.task.RegionManagerLoader;
@@ -68,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.storage.DriverType;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.*;
import com.sk89q.worldguard.protection.regions.ProtectedRegion.CircularInheritanceException;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.util.Enums;
@@ -133,7 +130,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "ng",
desc = "Defines a region",
min = 1)
public void define(CommandContext args, Actor sender) throws CommandException {
public void define(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender);
@@ -142,11 +139,12 @@ public final class RegionCommands extends RegionCommandsBase {
throw new CommandPermissionsException();
}
String id = checkRegionId(args.getString(0), false);
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
RegionManager manager = checkRegionManager(player.getWorld());
World world = player.getWorld();
RegionManager manager = checkRegionManager(world);
checkRegionDoesNotExist(manager, id, true);
checkRegionDoesNotExist(sender, manager, id, true);
ProtectedRegion region;
@@ -159,16 +157,18 @@ public final class RegionCommands extends RegionCommandsBase {
RegionAdder task = new RegionAdder(manager, region);
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)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess((Component) null,
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);
informNewUser(sender, manager, 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());
}
@@ -184,16 +184,17 @@ public final class RegionCommands extends RegionCommandsBase {
desc = "Re-defines the shape of a region",
flags = "g",
min = 1, max = 1)
public void redefine(CommandContext args, Actor sender) throws CommandException {
public void redefine(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender);
String id = checkRegionId(args.getString(0), false);
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
RegionManager manager = checkRegionManager(player.getWorld());
World world = player.getWorld();
RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(manager, id, false);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
// Check permissions
if (!getPermissionModel(player).mayRedefine(existing)) {
@@ -212,17 +213,19 @@ public final class RegionCommands extends RegionCommandsBase {
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)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... " + description + ")")
.onSuccess((Component) null,
t -> {
player.print(String.format("Region '%s' has been updated with a new area.", region.getId()));
player.print(String.format("Region '%s' has been updated with a new area.", friendlyName));
warnAboutDimensions(player, region);
informNewUser(player, manager, 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());
}
@@ -240,7 +243,7 @@ public final class RegionCommands extends RegionCommandsBase {
usage = "<id>",
desc = "Claim a region",
min = 1, max = 1)
public void claim(CommandContext args, Actor sender) throws CommandException {
public void claim(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender);
@@ -251,11 +254,11 @@ public final class RegionCommands extends RegionCommandsBase {
throw new CommandPermissionsException();
}
String id = checkRegionId(args.getString(0), false);
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
RegionManager manager = checkRegionManager(player.getWorld());
checkRegionDoesNotExist(manager, id, false);
checkRegionDoesNotExist(sender, manager, id, false);
ProtectedRegion region = checkRegionFromSelection(player, id);
WorldConfiguration wcfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(player.getWorld());
@@ -317,11 +320,12 @@ public final class RegionCommands extends RegionCommandsBase {
task.setLocatorPolicy(UserLocatorPolicy.UUID_ONLY);
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)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), 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())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
}
@@ -337,7 +341,7 @@ public final class RegionCommands extends RegionCommandsBase {
usage = "[id]",
desc = "Load a region as a WorldEdit selection",
min = 0, max = 1)
public void select(CommandContext args, Actor sender) throws CommandException {
public void select(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
LocalPlayer player = worldGuard.checkPlayer(sender);
RegionManager manager = checkRegionManager(player.getWorld());
ProtectedRegion existing;
@@ -346,7 +350,8 @@ public final class RegionCommands extends RegionCommandsBase {
if (args.argsLength() == 0) {
existing = checkRegionStandingIn(manager, player, "/rg select %id%");
} else {
existing = checkExistingRegion(manager, args.getString(0), false);
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
existing = checkExistingRegion(sender, manager, id);
}
// Check permissions
@@ -370,7 +375,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "usw:",
desc = "Get information about a region",
min = 0, max = 1)
public void info(CommandContext args, Actor sender) throws CommandException {
public void info(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -388,7 +393,8 @@ public final class RegionCommands extends RegionCommandsBase {
existing = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg info -w \"" + world.getName() + "\" %id%" + (args.hasFlag('u') ? " -u" : "") + (args.hasFlag('s') ? " -s" : ""));
} else { // Get region from the ID
existing = checkExistingRegion(manager, args.getString(0), true);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
existing = checkExistingRegion(sender, manager, id);
}
// Check permissions
@@ -484,7 +490,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "g:w:eh:",
desc = "Set flags",
min = 2)
public void flag(CommandContext args, Actor sender) throws CommandException {
public void flag(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -504,13 +510,13 @@ public final class RegionCommands extends RegionCommandsBase {
// Lookup the existing region
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
if (!permModel.maySetFlag(existing)) {
throw new CommandPermissionsException();
}
String regionId = existing.getId();
Flag<?> foundFlag = Flags.fuzzyMatchFlag(flagRegistry, flagName);
@@ -518,7 +524,7 @@ public final class RegionCommands extends RegionCommandsBase {
// can use, and do nothing afterwards
if (foundFlag == null) {
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.")
.onSuccess((Component) null, sender::print)
.onFailure((Component) null, WorldGuard.getInstance().getExceptionConverter())
@@ -575,7 +581,8 @@ public final class RegionCommands extends RegionCommandsBase {
}
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
@@ -590,7 +597,8 @@ public final class RegionCommands extends RegionCommandsBase {
}
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.)");
}
}
@@ -626,7 +634,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "p:w:",
desc = "View region flags",
min = 0, max = 2)
public void flagHelper(CommandContext args, Actor sender) throws CommandException {
public void flagHelper(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
World world = checkWorld(args, sender, 'w'); // Get the world
// Lookup the existing region
@@ -640,7 +648,8 @@ public final class RegionCommands extends RegionCommandsBase {
region = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg flags -w \"" + world.getName() + "\" %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);
@@ -676,7 +685,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "w:",
desc = "Set the priority of a region",
min = 2, max = 2)
public void setPriority(CommandContext args, Actor sender) throws CommandException {
public void setPriority(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -684,7 +693,8 @@ public final class RegionCommands extends RegionCommandsBase {
// Lookup the existing region
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
if (!getPermissionModel(sender).maySetPriority(existing)) {
@@ -693,7 +703,8 @@ public final class RegionCommands extends RegionCommandsBase {
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).");
}
/**
@@ -708,7 +719,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "w:",
desc = "Set the parent of a region",
min = 1, max = 2)
public void setParent(CommandContext args, Actor sender) throws CommandException {
public void setParent(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -719,9 +730,11 @@ public final class RegionCommands extends RegionCommandsBase {
RegionManager manager = checkRegionManager(world);
// 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) {
parent = checkExistingRegion(manager, args.getString(1), false);
RegionIdentifier parentId = processRegionId(sender, args.getString(1), false);
parent = checkExistingRegion(sender, manager, parentId);
} else {
parent = null;
}
@@ -735,11 +748,15 @@ public final class RegionCommands extends RegionCommandsBase {
child.setParent(parent);
} catch (CircularInheritanceException e) {
// Tell the user what's wrong
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), parent, null, sender);
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();
printout.append(SubtleFormat.wrap("(Current inheritance on '", parent.getId(), "':")).newline();
printout.append(SubtleFormat.wrap("(Current inheritance on '", parentFriendlyName, "':")).newline();
printout.appendParentTree(true);
printout.append(SubtleFormat.wrap(")"));
printout.send(sender);
@@ -747,8 +764,9 @@ public final class RegionCommands extends RegionCommandsBase {
}
// Tell the user the current inheritance
String childFriendlyName = childId.getDisplayName(sender);
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), child, null, sender);
printout.append(TextComponent.of("Inheritance set for region '" + child.getId() + "'.", TextColor.LIGHT_PURPLE));
printout.append(TextComponent.of("Inheritance set for region '" + childFriendlyName + "'.", TextColor.LIGHT_PURPLE));
if (parent != null) {
printout.newline();
printout.append(SubtleFormat.wrap("(Current inheritance:")).newline();
@@ -772,7 +790,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "fuw:",
desc = "Remove a region",
min = 1, max = 1)
public void remove(CommandContext args, Actor sender) throws CommandException {
public void remove(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -781,7 +799,8 @@ public final class RegionCommands extends RegionCommandsBase {
// Lookup the existing region
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
if (!getPermissionModel(sender).mayDelete(existing)) {
@@ -798,12 +817,15 @@ public final class RegionCommands extends RegionCommandsBase {
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)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), description)
.sendMessageAfterDelay("Please wait... removing region.")
.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)))
.onFailure("Failed to remove region", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
@@ -838,10 +860,6 @@ public final class RegionCommands extends RegionCommandsBase {
if (world != null) {
RegionManager manager = checkRegionManager(world);
if (manager == null) {
throw new CommandException("No region manager exists for world '" + world.getName() + "'.");
}
final String description = String.format("Loading region data for '%s'.", world.getName());
AsyncCommandBuilder.wrap(new RegionManagerLoader(manager), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
@@ -898,10 +916,6 @@ public final class RegionCommands extends RegionCommandsBase {
if (world != null) {
RegionManager manager = checkRegionManager(world);
if (manager == null) {
throw new CommandException("No region manager exists for world '" + world.getName() + "'.");
}
final String description = String.format("Saving region data for '%s'.", world.getName());
AsyncCommandBuilder.wrap(new RegionManagerSaver(manager), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
@@ -1064,14 +1078,15 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "sw:",
desc = "Teleports you to the location associated with the region.",
min = 1, max = 1)
public void teleport(CommandContext args, Actor sender) throws CommandException {
public void teleport(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
LocalPlayer player = worldGuard.checkPlayer(sender);
Location teleportLocation;
// Lookup the existing region
World world = checkWorld(args, player, 'w');
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
if (!getPermissionModel(player).mayTeleportTo(existing)) {
@@ -1094,9 +1109,10 @@ public final class RegionCommands extends RegionCommandsBase {
}
}
String friendlyName = id.getDisplayName(sender);
player.teleport(teleportLocation,
"Teleported you to the region '" + existing.getId() + "'.",
"Unable to teleport to region '" + existing.getId() + "'.");
"Teleported you to the region '" + friendlyName + "'.",
"Unable to teleport to region '" + friendlyName + "'.");
}
@Command(aliases = {"toggle-bypass", "bypass"},
@@ -1119,12 +1135,12 @@ public final class RegionCommands extends RegionCommandsBase {
private final RegionPermissionModel permModel;
private final ProtectedRegion existing;
private final World world;
private final String regionId;
private final RegionIdentifier regionId;
private final Actor sender;
private final String flagName;
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.permModel = permModel;
this.existing = existing;
@@ -1156,9 +1172,10 @@ public final class RegionCommands extends RegionCommandsBase {
for (int i = 0; i < flagList.size(); i++) {
String flag = flagList.get(i);
String qualifiedName = regionId.getQualifiedName();
builder.append(TextComponent.of(flag, i % 2 == 0 ? TextColor.GRAY : TextColor.WHITE)
.hoverEvent(clickToSet).clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg flag -w \"" + world.getName() + "\" " + regionId + " " + flag + " ")));
"/rg flag -w \"" + world.getName() + "\" " + qualifiedName + " " + flag + " ")));
if (i < flagList.size() + 1) {
builder.append(TextComponent.of(", "));
}
@@ -1168,10 +1185,12 @@ public final class RegionCommands extends RegionCommandsBase {
.append(TextComponent.newline())
.append(builder.build());
if (sender.isPlayer()) {
String friendlyName = regionId.getDisplayName(sender);
String qualifiedName = regionId.getQualifiedName();
return ret.append(TextComponent.of("Or use the command ", TextColor.LIGHT_PURPLE)
.append(TextComponent.of("/rg flags " + regionId, TextColor.AQUA)
.append(TextComponent.of("/rg flags " + friendlyName, TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg flags -w \"" + world.getName() + "\" " + regionId))));
"/rg flags -w \"" + world.getName() + "\" " + qualifiedName))));
}
return ret;
}
@@ -20,6 +20,7 @@
package com.sk89q.worldguard.commands.region;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.IncompleteRegionException;
@@ -32,6 +33,8 @@ import com.sk89q.worldedit.regions.Polygonal2DRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
@@ -46,13 +49,13 @@ import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.FlagContext;
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.protection.regions.*;
import com.sk89q.worldguard.util.profile.Profile;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
class RegionCommandsBase {
@@ -74,9 +77,9 @@ class RegionCommandsBase {
* Gets the world from the given flag, or falling back to the the current player
* if the sender is a player, otherwise reporting an error.
*
* @param args the arguments
* @param args the arguments
* @param sender the sender
* @param flag the flag (such as 'w')
* @param flag the flag (such as 'w')
* @return a world
* @throws CommandException on error
*/
@@ -92,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.
*
* @param id the id
* @param id the id
* @param allowGlobal whether __global__ is allowed
* @return the id given
* @throws CommandException thrown on an error
*/
@Deprecated
protected static String checkRegionId(String id, boolean allowGlobal) throws CommandException {
if (!ProtectedRegion.isValidId(id)) {
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.");
}
checkName(id, allowGlobal);
return id;
}
/**
* Validate a region namespace.
*
* @param namespace the namespace name
* @throws CommandException thrown on an error
*/
protected static void checkNamespace(String namespace) throws CommandException {
if (!RegionIdentifier.isValidNamespace(namespace)) {
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
* {@link CommandException}.
@@ -125,6 +290,7 @@ class RegionCommandsBase {
* @param allowGlobal true to allow selecting __global__
* @throws CommandException thrown if no region is found by the given name
*/
@Deprecated
protected static ProtectedRegion checkExistingRegion(RegionManager regionManager, String id, boolean allowGlobal) throws CommandException {
// Validate the id
checkRegionId(id, allowGlobal);
@@ -147,6 +313,36 @@ class RegionCommandsBase {
return region;
}
/**
* Get a protected region by a given name, otherwise throw a
* {@link CommandException}.
*
* <p>This also validates the region ID.</p>
*
* @param actor the associated player
* @param regionManager the region manager
* @param id the name to search
* @throws CommandException thrown if no region is found by the given name
*/
protected static ProtectedRegion checkExistingRegion(Actor actor, RegionManager regionManager, RegionIdentifier id) throws CommandException {
ProtectedRegion region = regionManager.getRegion(id);
// No region found!
if (region == null) {
// But we want a __global__, so let's create one
if (id.getQualifiedName().equals(":__global__")) {
region = new GlobalProtectedRegion(id);
regionManager.addRegion(region);
return region;
}
throw new CommandException(
"No region could be found with the name of '" + id.getDisplayName(actor) + "'.");
}
return region;
}
/**
* Get the region at the player's location, if possible.
@@ -201,10 +397,12 @@ class RegionCommandsBase {
builder.append(TextComponent.of(", "));
}
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%")) {
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);
}
@@ -241,10 +439,23 @@ class RegionCommandsBase {
* @param id the ID
* @throws CommandException thrown if the ID already exists
*/
@Deprecated
protected static void checkRegionDoesNotExist(RegionManager manager, String id, boolean mayRedefine) throws CommandException {
checkRegionDoesNotExist(null, manager, new RegionIdentifier(id), mayRedefine);
}
/**
* Check that a region with the given ID does not already exist.
*
* @param actor the associated player
* @param manager the manager
* @param id the identifier
* @throws CommandException thrown if the ID already exists
*/
protected static void checkRegionDoesNotExist(Actor actor, RegionManager manager, RegionIdentifier id, boolean mayRedefine) throws CommandException {
if (manager.hasRegion(id)) {
throw new CommandException("A region with that name already exists. Please choose another name." +
(mayRedefine ? " To change the shape, use /region redefine " + id + "." : ""));
(mayRedefine ? " To change the shape, use /region redefine " + id.getDisplayName(actor) + "." : ""));
}
}
@@ -277,7 +488,20 @@ class RegionCommandsBase {
* @return a new region
* @throws CommandException thrown on an error
*/
@Deprecated
protected static ProtectedRegion checkRegionFromSelection(LocalPlayer player, String id) throws CommandException {
return checkRegionFromSelection(player, new RegionIdentifier(id));
}
/**
* Create a {@link ProtectedRegion} from the player's selection.
*
* @param player the player
* @param id the identifier of the new region
* @return a new region
* @throws CommandException thrown on an error
*/
protected static ProtectedRegion checkRegionFromSelection(LocalPlayer player, RegionIdentifier id) throws CommandException {
Region selection = checkSelection(player);
// Detect the type of region from WorldEdit
@@ -341,6 +565,24 @@ class RegionCommandsBase {
}
}
/**
* Inform a user if the region overlaps spawn protection.
*
* @param sender the sender to send the message to
* @param world the world the region is in
* @param region the region
*/
protected static void checkSpawnOverlap(Actor sender, World world, ProtectedRegion region) {
ProtectedRegion spawn = WorldGuard.getInstance().getPlatform().getSpawnProtection(world);
if (spawn != null) {
if (!spawn.getIntersectingRegions(ImmutableList.of(region)).isEmpty()) {
sender.print(ErrorFormat.wrap("Warning!")
.append(TextComponent.of(" This region overlaps vanilla's spawn protection. WorldGuard cannot " +
"override this, and only server operators will be able to interact with this area.")));
}
}
}
/**
* Set a player's selection to a given region.
*
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.commands.region;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.math.BlockVector3;
@@ -58,6 +59,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
@Nullable
private final ProfileCache cache;
private final TextComponentProducer builder = new TextComponentProducer();
private final Actor actor;
private final RegionPermissionModel perms;
/**
@@ -70,6 +72,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
this.world = world;
this.region = region;
this.cache = cache;
this.actor = actor;
this.perms = actor != null && actor.isPlayer() ? new RegionPermissionModel(actor) : null;
}
@@ -85,8 +88,10 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
*/
public void appendBasics() {
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(region.getType().getName()));
@@ -76,6 +76,7 @@ public abstract class ConfigurationManager {
public boolean migrateRegionsToUuid;
public boolean keepUnresolvedNames;
public boolean particleEffects;
public boolean useNamespaces;
@Unreported public Map<String, String> hostKeys = new HashMap<>();
public boolean hostKeysAllowFMLClients;
@@ -63,6 +63,7 @@ public abstract class YamlConfigurationManager extends ConfigurationManager {
usePlayerMove = config.getBoolean("use-player-move-event", true);
usePlayerTeleports = config.getBoolean("use-player-teleports", true);
particleEffects = config.getBoolean("use-particle-effects", true);
useNamespaces = config.getBoolean("use-namespaces", true);
deopOnJoin = config.getBoolean("security.deop-everyone-on-join", false);
blockInGameOp = config.getBoolean("security.block-in-game-op-command", false);
@@ -26,6 +26,7 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import javax.annotation.Nullable;
@@ -21,15 +21,18 @@ package com.sk89q.worldguard.internal.platform;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.report.ReportList;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.config.ConfigurationManager;
import com.sk89q.worldguard.protection.flags.FlagContext;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.session.SessionManager;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldguard.util.profile.resolver.ProfileService;
import javax.annotation.Nullable;
import java.nio.file.Path;
/**
@@ -155,4 +158,15 @@ public interface WorldGuardPlatform {
* Internal use.
*/
ProfileService createProfileService(ProfileCache profileCache);
/**
* Get a region that encompasses the Vanilla spawn protection for the given world, if applicable.
*
* @param world world to check spawn protection of
* @return a region, or null if not applicable
*/
@Nullable
default ProtectedRegion getSpawnProtection(World world) {
return null;
}
}
@@ -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.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import com.sk89q.worldguard.protection.util.RegionCollectionConsumer;
import com.sk89q.worldguard.util.Normal;
@@ -242,10 +243,22 @@ public final class RegionManager {
* @param id the name of the region
* @return true if this index contains the region
*/
@Deprecated
public boolean hasRegion(String id) {
return index.contains(id);
}
/**
* Return whether the index contains a region with the given identifier,
* with quality determined by {@link Normal}.
*
* @param id the region identifier
* @return true if this index contains the region
*/
public boolean hasRegion(RegionIdentifier id) {
return index.contains(id.getLegacyQualifiedName());
}
/**
* Get the region named by the given name (equality determined using
* {@link Normal}).
@@ -254,11 +267,24 @@ public final class RegionManager {
* @return a region or {@code null}
*/
@Nullable
@Deprecated
public ProtectedRegion getRegion(String id) {
checkNotNull(id);
return index.get(id);
}
/**
* Get the region named y the given id.
*
* @param id the region identifier
* @return a region or {@code null}
*/
@Nullable
public ProtectedRegion getRegion(RegionIdentifier id) {
checkNotNull(id);
return index.get(id.getLegacyQualifiedName());
}
/**
* @deprecated Use exact ids with {@link #getRegion}
*/
@@ -70,12 +70,13 @@ public class HashMapIndex extends AbstractRegionIndex implements ConcurrentRegio
region.setDirty(true);
synchronized (lock) {
String normalId = normalize(region.getId());
String newFullId = region.getIdentifier().getLegacyQualifiedName();
String normalId = normalize(newFullId);
ProtectedRegion existing = regions.get(normalId);
// 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);
}
@@ -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;
}
}
}
@@ -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));
}
}
}
}
@@ -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>";
}
}
}
@@ -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);
}
@@ -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());
}
}
@@ -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());
}
}
@@ -19,56 +19,32 @@
package com.sk89q.worldguard.protection.managers.storage.file;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.util.yaml.YAMLFormat;
import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.FlagUtil;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabaseUtils;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import com.sk89q.worldguard.protection.regions.*;
import org.yaml.snakeyaml.parser.ParserException;
import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.*;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldguard.protection.managers.storage.file.YamlCommon.YAML_GLOBAL_NAMESPACE_NAME;
/**
* A store that persists regions in a YAML-encoded file.
*/
public class YamlRegionFile implements RegionDatabase {
private static final Logger log = Logger.getLogger(YamlRegionFile.class.getCanonicalName());
private static final Yaml ERROR_DUMP_YAML;
private static final String FILE_HEADER = "#\r\n" +
"# WorldGuard regions file\r\n" +
"#\r\n" +
@@ -81,17 +57,19 @@ public class YamlRegionFile implements RegionDatabase {
"# REMEMBER TO KEEP PERIODICAL BACKUPS.\r\n" +
"#";
private final String name;
private final File file;
private static final List<YamlReader> YAML_READERS = new ArrayList<>();
static {
DumperOptions options = new DumperOptions();
options.setIndent(4);
options.setDefaultFlowStyle(FlowStyle.AUTO);
ERROR_DUMP_YAML = new Yaml(new SafeConstructor(), new Representer(), options);
// IMPORTANT: For best performance, add these in reverse order.
// We always want the latest version to be attempted first, so that once migrated, we are checking
// one version, not n.
YAML_READERS.add(new YamlReaderVersionTwo());
YAML_READERS.add(new YamlReaderVersionOne());
}
private final String name;
private final File file;
/**
* Create a new instance.
*
@@ -112,80 +90,22 @@ public class YamlRegionFile implements RegionDatabase {
@Override
public Set<ProtectedRegion> loadAll(FlagRegistry flagRegistry) throws StorageException {
Map<String, ProtectedRegion> loaded = new HashMap<>();
YAMLProcessor config = createYamlProcessor(file);
try {
config.load();
} catch (FileNotFoundException e) {
return new HashSet<>(loaded.values());
return new HashSet<>();
} catch (IOException | ParserException e) {
throw new StorageException("Failed to load region data from '" + file + "'", e);
}
Map<String, YAMLNode> regionData = config.getNodes("regions");
if (regionData == null) {
return Collections.emptySet(); // No regions are even configured
}
Map<ProtectedRegion, String> parentSets = new LinkedHashMap<>();
for (Map.Entry<String, YAMLNode> entry : regionData.entrySet()) {
String id = entry.getKey();
YAMLNode node = entry.getValue();
String type = node.getString("type");
ProtectedRegion region;
try {
if (type == null) {
log.warning("Undefined region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
continue;
} else if (type.equals("cuboid")) {
Vector3 pt1 = checkNotNull(node.getVector("min"));
Vector3 pt2 = checkNotNull(node.getVector("max"));
BlockVector3 min = pt1.getMinimum(pt2).toBlockPoint();
BlockVector3 max = pt1.getMaximum(pt2).toBlockPoint();
region = new ProtectedCuboidRegion(id, min, max);
} else if (type.equals("poly2d")) {
Integer minY = checkNotNull(node.getInt("min-y"));
Integer maxY = checkNotNull(node.getInt("max-y"));
List<BlockVector2> points = node.getBlockVector2List("points", null);
region = new ProtectedPolygonalRegion(id, points, minY, maxY);
} else if (type.equals("global")) {
region = new GlobalProtectedRegion(id);
} else {
log.warning("Unknown region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
continue;
}
Integer priority = checkNotNull(node.getInt("priority"));
region.setPriority(priority);
setFlags(flagRegistry, region, node.getNode("flags"));
region.setOwners(parseDomain(node.getNode("owners")));
region.setMembers(parseDomain(node.getNode("members")));
loaded.put(id, region);
String parentId = node.getString("parent");
if (parentId != null) {
parentSets.put(region, parentId);
}
} catch (NullPointerException e) {
log.log(Level.WARNING,
"Unexpected NullPointerException encountered during parsing for the region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) +
"\n\nNote: This region will disappear as a result!", e);
for (YamlReader reader : YAML_READERS) {
if (reader.canLoad(config)) {
return reader.load(flagRegistry, config);
}
}
// Relink parents
RegionDatabaseUtils.relinkParents(loaded, parentSets);
return new HashSet<>(loaded.values());
throw new IllegalStateException("No YAML reader was registered that understands the saved region information");
}
@Override
@@ -197,13 +117,25 @@ public class YamlRegionFile implements RegionDatabase {
config.clear();
config.setProperty("version", YAML_READERS.get(0).getVersion());
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) {
Map<String, Object> nodeMap = new HashMap<>();
map.put(region.getId(), nodeMap);
YAMLNode node = new YAMLNode(nodeMap, false);
RegionIdentifier identifier = region.getIdentifier();
String internalNamespace = identifier.getNamespace().orElse(YAML_GLOBAL_NAMESPACE_NAME);
YAMLNode namespaceNode = namespaceMap.compute(internalNamespace, (ignored, existingNamespaceNode) -> {
if (existingNamespaceNode == null) {
existingNamespaceNode = regionsNode.addNode(internalNamespace);
}
return existingNamespaceNode;
});
YAMLNode node = namespaceNode.addNode(identifier.getName());
if (region instanceof ProtectedCuboidRegion) {
ProtectedCuboidRegion cuboid = (ProtectedCuboidRegion) region;
@@ -238,7 +170,7 @@ public class YamlRegionFile implements RegionDatabase {
ProtectedRegion parent = region.getParent();
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");
}
private DefaultDomain parseDomain(YAMLNode node) {
if (node == null) {
return new DefaultDomain();
}
DefaultDomain domain = new DefaultDomain();
for (String name : node.getStringList("players", null)) {
if (!name.isEmpty()) {
domain.addPlayer(name);
}
}
for (String stringId : node.getStringList("unique-ids", null)) {
try {
domain.addPlayer(UUID.fromString(stringId));
} catch (IllegalArgumentException e) {
log.log(Level.WARNING, "Failed to parse UUID '" + stringId + "'", e);
}
}
for (String name : node.getStringList("groups", null)) {
if (!name.isEmpty()) {
domain.addGroup(name);
}
}
return domain;
}
private Map<String, Object> getFlagData(ProtectedRegion region) {
return FlagUtil.marshal(region.getFlags());
}
private void setFlags(FlagRegistry flagRegistry, ProtectedRegion region, YAMLNode flagsData) {
if (flagsData != null) {
region.setFlags(flagRegistry.unmarshal(flagsData.getMap(), true));
}
}
private Map<String, Object> getDomainData(DefaultDomain domain) {
Map<String, Object> domainData = new HashMap<>();
@@ -331,19 +227,4 @@ public class YamlRegionFile implements RegionDatabase {
checkNotNull(file);
return new YAMLProcessor(file, false, YAMLFormat.COMPACT);
}
/**
* Dump the given object as YAML for debugging purposes.
*
* @param object the object
* @return the YAML string or an error string if dumping fals
*/
private static String toYamlOutput(Object object) {
try {
return ERROR_DUMP_YAML.dump(object).replaceAll("(?m)^", "\t");
} catch (Throwable t) {
return "<error while dumping object>";
}
}
}
@@ -44,6 +44,7 @@ public class GlobalProtectedRegion extends ProtectedRegion {
*
* @param id the ID
*/
@Deprecated
public GlobalProtectedRegion(String id) {
this(id, false);
}
@@ -54,7 +55,29 @@ public class GlobalProtectedRegion extends ProtectedRegion {
* @param id the ID
* @param transientRegion whether this region should only be kept in memory and not be saved
*/
@Deprecated
public GlobalProtectedRegion(String id, boolean transientRegion) {
this(new RegionIdentifier(id), transientRegion);
}
/**
* Create a new instance.<br>
* Equivalent to {@link #GlobalProtectedRegion(String, boolean) GlobalProtectedRegion(id, false)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the region identifier
*/
public GlobalProtectedRegion(RegionIdentifier id) {
this(id, false);
}
/**
* Create a new instance.
*
* @param id the region identifier
* @param transientRegion whether this region should only be kept in memory and not be saved
*/
public GlobalProtectedRegion(RegionIdentifier id, boolean transientRegion) {
super(id, transientRegion);
min = BlockVector3.ZERO;
max = BlockVector3.ZERO;
@@ -47,6 +47,7 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
@Deprecated
public ProtectedCuboidRegion(String id, BlockVector3 pt1, BlockVector3 pt2) {
this(id, false, pt1, pt2);
}
@@ -59,7 +60,34 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
@Deprecated
public ProtectedCuboidRegion(String id, boolean transientRegion, BlockVector3 pt1, BlockVector3 pt2) {
this(new RegionIdentifier(id), transientRegion, pt1, pt2);
}
/**
* Construct a new instance of this cuboid region.<br>
* Equivalent to {@link #ProtectedCuboidRegion(RegionIdentifier, boolean, BlockVector3, BlockVector3)
* ProtectedCuboidRegion(id, false, pt1, pt2)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the region identifier
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
public ProtectedCuboidRegion(RegionIdentifier id, BlockVector3 pt1, BlockVector3 pt2) {
this(id, false, pt1, pt2);
}
/**
* Construct a new instance of this cuboid region.
*
* @param id the region identifier
* @param transientRegion whether this region should only be kept in memory and not be saved
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
public ProtectedCuboidRegion(RegionIdentifier id, boolean transientRegion, BlockVector3 pt1, BlockVector3 pt2) {
super(id, transientRegion);
setMinMaxPoints(pt1, pt2);
}
@@ -47,6 +47,7 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
@Deprecated
public ProtectedPolygonalRegion(String id, List<BlockVector2> points, int minY, int maxY) {
this(id, false, points, minY, maxY);
}
@@ -60,7 +61,37 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
@Deprecated
public ProtectedPolygonalRegion(String id, boolean transientRegion, List<BlockVector2> points, int minY, int maxY) {
this(new RegionIdentifier(id), transientRegion, points, minY, maxY);
}
/**
* Construct a new instance of this polygonal region.<br>
* Equivalent to {@link #ProtectedPolygonalRegion(RegionIdentifier, boolean, List, int, int)
* ProtectedPolygonalRegion(id, false, points, minY, maxY)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the region identifier
* @param points a {@link List} of points that this region should contain
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
public ProtectedPolygonalRegion(RegionIdentifier id, List<BlockVector2> points, int minY, int maxY) {
this(id, false, points, minY, maxY);
}
/**
* Construct a new instance of this polygonal region.
*
* @param id the region identifier
* @param transientRegion whether this region should only be kept in memory and not be saved
* @param points a {@link List} of points that this region should contain
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
public ProtectedPolygonalRegion(RegionIdentifier id, boolean transientRegion, List<BlockVector2> points,
int minY, int maxY) {
super(id, transientRegion);
ImmutableList<BlockVector2> immutablePoints = ImmutableList.copyOf(points);
setMinMaxPoints(immutablePoints, minY, maxY);
@@ -28,7 +28,6 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.util.ChangeTracked;
import com.sk89q.worldguard.util.Normal;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
@@ -37,7 +36,6 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
@@ -50,12 +48,11 @@ import javax.annotation.Nullable;
public abstract class ProtectedRegion implements ChangeTracked, Comparable<ProtectedRegion> {
public static final String GLOBAL_REGION = "__global__";
private static final Pattern VALID_ID_PATTERN = Pattern.compile("^[A-Za-z0-9_,'\\-\\+/]{1,}$");
protected BlockVector3 min;
protected BlockVector3 max;
private final String id;
private final RegionIdentifier id;
private final boolean transientRegion;
private int priority = 0;
private ProtectedRegion parent;
@@ -67,18 +64,13 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
/**
* 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
* @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);
if (!isValidId(id)) {
throw new IllegalArgumentException("Invalid region ID: " + id);
}
this.id = Normal.normalize(id);
this.id = id;
this.transientRegion = transientRegion;
}
@@ -119,7 +111,17 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
*
* @return the name
*/
@Deprecated
public String getId() {
return id.getLegacyQualifiedName();
}
/**
* Gets the identifier info for this region.
*
* @return the identifier info
*/
public RegionIdentifier getIdentifier() {
return id;
}
@@ -734,9 +736,9 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
* @param id the id to check
* @return whether the region id given is valid
*/
@Deprecated
public static boolean isValidId(String id) {
checkNotNull(id);
return VALID_ID_PATTERN.matcher(id).matches();
return RegionIdentifier.isValidName(id);
}
/**
@@ -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();
}
}
@@ -33,6 +33,7 @@ import com.sk89q.worldedit.world.weather.WeatherType;
import org.junit.Ignore;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
@@ -63,6 +64,11 @@ public class TestPlayer extends AbstractPlayerActor implements LocalPlayer {
return uuid;
}
@Override
public String getDefaultNamespace() {
return null;
}
@Override
public boolean hasGroup(String group) {
return groups.contains(group.toLowerCase());
@@ -213,6 +219,11 @@ public class TestPlayer extends AbstractPlayerActor implements LocalPlayer {
}
@Override
public Locale getLocale() {
return Locale.ENGLISH;
}
@Override
public String[] getGroups() {
return groups.toArray(new String[groups.size()]);