3333import com .sk89q .worldedit .regions .Region ;
3434import com .sk89q .worldedit .regions .selector .CuboidRegionSelector ;
3535import com .sk89q .worldedit .regions .selector .Polygonal2DRegionSelector ;
36+ import com .sk89q .worldedit .util .auth .AuthorizationException ;
3637import com .sk89q .worldedit .util .formatting .component .ErrorFormat ;
3738import com .sk89q .worldedit .util .formatting .component .SubtleFormat ;
3839import com .sk89q .worldedit .util .formatting .text .TextComponent ;
4950import com .sk89q .worldguard .protection .flags .FlagContext ;
5051import com .sk89q .worldguard .protection .flags .InvalidFlagFormat ;
5152import 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 ;
5856import java .util .Set ;
57+ import java .util .UUID ;
5958import java .util .stream .Collectors ;
6059
6160class 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
0 commit comments