Skip to content

Commit 02303bd

Browse files
committed
Initial work on namespaces
1 parent b835ee3 commit 02303bd

File tree

16 files changed

+689
-188
lines changed

16 files changed

+689
-188
lines changed

worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/RegionCommands.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.sk89q.worldedit.extension.platform.Actor;
3333
import com.sk89q.worldedit.extension.platform.Capability;
3434
import com.sk89q.worldedit.util.Location;
35+
import com.sk89q.worldedit.util.auth.AuthorizationException;
3536
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
3637
import com.sk89q.worldedit.util.formatting.component.LabelFormat;
3738
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
@@ -68,11 +69,8 @@
6869
import com.sk89q.worldguard.protection.managers.migration.UUIDMigration;
6970
import com.sk89q.worldguard.protection.managers.storage.DriverType;
7071
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
71-
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
72-
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
73-
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
72+
import com.sk89q.worldguard.protection.regions.*;
7473
import com.sk89q.worldguard.protection.regions.ProtectedRegion.CircularInheritanceException;
75-
import com.sk89q.worldguard.protection.regions.RegionContainer;
7674
import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy;
7775
import com.sk89q.worldguard.session.Session;
7876
import com.sk89q.worldguard.util.Enums;
@@ -133,7 +131,7 @@ public RegionCommands(WorldGuard worldGuard) {
133131
flags = "ng",
134132
desc = "Defines a region",
135133
min = 1)
136-
public void define(CommandContext args, Actor sender) throws CommandException {
134+
public void define(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
137135
warnAboutSaveFailures(sender);
138136
LocalPlayer player = worldGuard.checkPlayer(sender);
139137

@@ -142,7 +140,7 @@ public void define(CommandContext args, Actor sender) throws CommandException {
142140
throw new CommandPermissionsException();
143141
}
144142

145-
String id = checkRegionId(args.getString(0), false);
143+
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
146144

147145
World world = player.getWorld();
148146
RegionManager manager = checkRegionManager(world);

worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/RegionCommandsBase.java

Lines changed: 163 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.sk89q.worldedit.regions.Region;
3434
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
3535
import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector;
36+
import com.sk89q.worldedit.util.auth.AuthorizationException;
3637
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
3738
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
3839
import com.sk89q.worldedit.util.formatting.text.TextComponent;
@@ -49,13 +50,11 @@
4950
import com.sk89q.worldguard.protection.flags.FlagContext;
5051
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
5152
import com.sk89q.worldguard.protection.managers.RegionManager;
52-
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
53-
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
54-
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
55-
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
56-
import com.sk89q.worldguard.protection.regions.RegionContainer;
53+
import com.sk89q.worldguard.protection.regions.*;
5754

55+
import java.util.Optional;
5856
import java.util.Set;
57+
import java.util.UUID;
5958
import java.util.stream.Collectors;
6059

6160
class RegionCommandsBase {
@@ -95,6 +94,25 @@ protected static World checkWorld(CommandContext args, Actor sender, char flag)
9594
}
9695
}
9796

97+
/**
98+
* Validate a region name.
99+
*
100+
* @param name the name
101+
* @param allowGlobal whether __global__ is allowed
102+
* @throws CommandException thrown on an error
103+
*/
104+
protected static void checkName(String name, boolean allowGlobal) throws CommandException {
105+
if (!RegionIdentifier.isValidName(name)) {
106+
throw new CommandException(
107+
"The region name of '" + name + "' contains characters that are not allowed.");
108+
}
109+
110+
if (!allowGlobal && name.equalsIgnoreCase("__global__")) { // Sorry, no global
111+
throw new CommandException(
112+
"Sorry, you can't use __global__ here.");
113+
}
114+
}
115+
98116
/**
99117
* Validate a region ID.
100118
*
@@ -103,18 +121,127 @@ protected static World checkWorld(CommandContext args, Actor sender, char flag)
103121
* @return the id given
104122
* @throws CommandException thrown on an error
105123
*/
124+
@Deprecated
106125
protected static String checkRegionId(String id, boolean allowGlobal) throws CommandException {
107-
if (!ProtectedRegion.isValidId(id)) {
126+
checkName(id, allowGlobal);
127+
return id;
128+
}
129+
130+
/**
131+
* Validate a region namespace.
132+
*
133+
* @param namespace the namespace name
134+
* @throws CommandException thrown on an error
135+
*/
136+
protected static void checkNamespace(String namespace) throws CommandException {
137+
if (!RegionIdentifier.isValidNamespace(namespace)) {
108138
throw new CommandException(
109-
"The region name of '" + id + "' contains characters that are not allowed.");
139+
"The region namespace of '" + namespace + "' contains characters that are not allowed.");
110140
}
141+
}
111142

112-
if (!allowGlobal && id.equalsIgnoreCase("__global__")) { // Sorry, no global
113-
throw new CommandException(
114-
"Sorry, you can't use __global__ here.");
143+
/**
144+
* Get the unqualified name from a possibly qualified region identifier.
145+
*
146+
* @param id the unprocessed region identifier
147+
* @return the unqualified name, or an empty string if not present
148+
*/
149+
protected static String getUnqualifiedName(String id) {
150+
int namespaceSeparatorIndex = id.lastIndexOf(':');
151+
if (namespaceSeparatorIndex == -1) {
152+
return id;
115153
}
116154

117-
return id;
155+
int unqualifiedNameStartIndex = namespaceSeparatorIndex + 1;
156+
if (unqualifiedNameStartIndex == id.length()) {
157+
return "";
158+
}
159+
160+
return id.substring(unqualifiedNameStartIndex);
161+
}
162+
163+
/**
164+
* Get the namespace name from a possibly qualified region identifier.
165+
*
166+
* @param id the unprocessed region identifier
167+
* @return an optional containing the namespace name, or an empty string if qualified,
168+
* if not qualified, an empty optional is returned
169+
*/
170+
protected static Optional<String> getNamespace(String id) {
171+
int namespaceSeparatorIndex = id.lastIndexOf(':');
172+
if (namespaceSeparatorIndex == -1) {
173+
return Optional.empty();
174+
}
175+
176+
return Optional.of(id.substring(0, namespaceSeparatorIndex));
177+
}
178+
179+
/***
180+
* Expand macros in the namespace name.
181+
*
182+
* @param namespace the unexpanded namespace name
183+
* @return the expanded namespace name
184+
*/
185+
protected static String expandNamespace(String namespace) {
186+
if (namespace.startsWith("#")) {
187+
String playerName = namespace.substring(1);
188+
// TODO: Resolve player uuid from name, and return that instead.
189+
return playerName;
190+
}
191+
192+
return namespace;
193+
}
194+
195+
/**
196+
* Get the default namespace for a given actor.
197+
*
198+
* @param sender the sender who's default namespace we intend to retrieve.
199+
* @return the default namespace
200+
*/
201+
protected static String getDefaultNamespace(Actor sender) {
202+
return sender.getUniqueId().toString();
203+
}
204+
205+
/**
206+
* Process a possibly qualified region identifier into a RegionIdentifier.
207+
*
208+
* This method takes a possibly qualified region identifier, and processes it, expanding any namespace macros,
209+
* running permissions checks, and validating the names for invalid character.
210+
*
211+
* @param sender the contextual sender to use for checks and macro expansions
212+
* @param id the possibly unqualified id
213+
* @param allowGlobal whether or not this method should allow use of the name __global__ name
214+
* @return the processed region id
215+
* @throws AuthorizationException if a permission check fails
216+
* @throws CommandException if a name validation check fails
217+
*/
218+
protected static RegionIdentifier processRegionId(Actor sender, String id, boolean allowGlobal) throws AuthorizationException, CommandException {
219+
String unqualifiedName = getUnqualifiedName(id);
220+
checkName(unqualifiedName, allowGlobal);
221+
222+
Optional<String> optProvidedNamespace = getNamespace(id).map(RegionCommandsBase::expandNamespace);
223+
String namespace = optProvidedNamespace.orElse(getDefaultNamespace(sender));
224+
checkNamespace(namespace);
225+
226+
// TODO use more informative permission checks
227+
228+
if (namespace.equals("")) {
229+
sender.checkPermission("worldguard.region.namespace.global");
230+
return new RegionIdentifier(null, unqualifiedName);
231+
}
232+
233+
try {
234+
UUID namespacePlayerId = UUID.fromString(namespace);
235+
if (namespacePlayerId.equals(sender.getUniqueId())) {
236+
sender.checkPermission("worldguard.region.namespace.player.self");
237+
} else {
238+
sender.checkPermission("worldguard.region.namespace.player.other");
239+
}
240+
} catch (IllegalArgumentException ex) {
241+
sender.checkPermission("worldguard.region.namespace." + namespace);
242+
}
243+
244+
return new RegionIdentifier(namespace, unqualifiedName);
118245
}
119246

120247
/**
@@ -244,7 +371,19 @@ protected static Region checkSelection(LocalPlayer player) throws CommandExcepti
244371
* @param id the ID
245372
* @throws CommandException thrown if the ID already exists
246373
*/
374+
@Deprecated
247375
protected static void checkRegionDoesNotExist(RegionManager manager, String id, boolean mayRedefine) throws CommandException {
376+
checkRegionDoesNotExist(manager, new RegionIdentifier(id), mayRedefine);
377+
}
378+
379+
/**
380+
* Check that a region with the given ID does not already exist.
381+
*
382+
* @param manager the manager
383+
* @param id the identifier
384+
* @throws CommandException thrown if the ID already exists
385+
*/
386+
protected static void checkRegionDoesNotExist(RegionManager manager, RegionIdentifier id, boolean mayRedefine) throws CommandException {
248387
if (manager.hasRegion(id)) {
249388
throw new CommandException("A region with that name already exists. Please choose another name." +
250389
(mayRedefine ? " To change the shape, use /region redefine " + id + "." : ""));
@@ -280,7 +419,20 @@ protected static RegionManager checkRegionManager(World world) throws CommandExc
280419
* @return a new region
281420
* @throws CommandException thrown on an error
282421
*/
422+
@Deprecated
283423
protected static ProtectedRegion checkRegionFromSelection(LocalPlayer player, String id) throws CommandException {
424+
return checkRegionFromSelection(player, new RegionIdentifier(id));
425+
}
426+
427+
/**
428+
* Create a {@link ProtectedRegion} from the player's selection.
429+
*
430+
* @param player the player
431+
* @param id the identifier of the new region
432+
* @return a new region
433+
* @throws CommandException thrown on an error
434+
*/
435+
protected static ProtectedRegion checkRegionFromSelection(LocalPlayer player, RegionIdentifier id) throws CommandException {
284436
Region selection = checkSelection(player);
285437

286438
// Detect the type of region from WorldEdit

worldguard-core/src/main/java/com/sk89q/worldguard/protection/managers/RegionManager.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
3535
import com.sk89q.worldguard.protection.managers.storage.StorageException;
3636
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
37+
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
3738
import com.sk89q.worldguard.protection.util.RegionCollectionConsumer;
3839
import com.sk89q.worldguard.util.Normal;
3940

@@ -242,10 +243,22 @@ public void addRegion(ProtectedRegion region) {
242243
* @param id the name of the region
243244
* @return true if this index contains the region
244245
*/
246+
@Deprecated
245247
public boolean hasRegion(String id) {
246248
return index.contains(id);
247249
}
248250

251+
/**
252+
* Return whether the index contains a region with the given identifier,
253+
* with quality determined by {@link Normal}.
254+
*
255+
* @param id the region identifier
256+
* @return true if this index contains the region
257+
*/
258+
public boolean hasRegion(RegionIdentifier id) {
259+
return index.contains(id.getQualifiedName());
260+
}
261+
249262
/**
250263
* Get the region named by the given name (equality determined using
251264
* {@link Normal}).

worldguard-core/src/main/java/com/sk89q/worldguard/protection/managers/index/HashMapIndex.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,13 @@ private void performAdd(ProtectedRegion region) {
7070
region.setDirty(true);
7171

7272
synchronized (lock) {
73-
String normalId = normalize(region.getId());
73+
String newFullId = region.getIdentifier().getQualifiedName();
74+
String normalId = normalize(newFullId);
7475

7576
ProtectedRegion existing = regions.get(normalId);
7677

7778
// Casing / form of ID has changed
78-
if (existing != null && !existing.getId().equals(region.getId())) {
79+
if (existing != null && !existing.getIdentifier().getQualifiedName().equals(newFullId)) {
7980
removed.add(existing);
8081
}
8182

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.sk89q.worldguard.protection.managers.storage.file;
2+
3+
import com.sk89q.util.yaml.YAMLNode;
4+
import com.sk89q.worldguard.domains.DefaultDomain;
5+
6+
import java.util.UUID;
7+
import java.util.logging.Level;
8+
9+
class DomainParser {
10+
public static class One {
11+
public static DefaultDomain parseDomain(YAMLNode node) {
12+
if (node == null) {
13+
return new DefaultDomain();
14+
}
15+
16+
DefaultDomain domain = new DefaultDomain();
17+
18+
for (String name : node.getStringList("players", null)) {
19+
if (!name.isEmpty()) {
20+
domain.addPlayer(name);
21+
}
22+
}
23+
24+
for (String stringId : node.getStringList("unique-ids", null)) {
25+
try {
26+
domain.addPlayer(UUID.fromString(stringId));
27+
} catch (IllegalArgumentException e) {
28+
YamlCommon.log.log(Level.WARNING, "Failed to parse UUID '" + stringId + "'", e);
29+
}
30+
}
31+
32+
for (String name : node.getStringList("groups", null)) {
33+
if (!name.isEmpty()) {
34+
domain.addGroup(name);
35+
}
36+
}
37+
38+
return domain;
39+
}
40+
}
41+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.sk89q.worldguard.protection.managers.storage.file;
2+
3+
import com.sk89q.util.yaml.YAMLNode;
4+
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
5+
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
6+
7+
class FlagParser {
8+
public static class One {
9+
public static void setFlags(FlagRegistry flagRegistry, ProtectedRegion region, YAMLNode flagsData) {
10+
if (flagsData != null) {
11+
region.setFlags(flagRegistry.unmarshal(flagsData.getMap(), true));
12+
}
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)