11package net .anweisen .utilities .bukkit .utils .misc ;
22
3+ import com .google .common .base .Preconditions ;
34import net .anweisen .utilities .common .logging .ILogger ;
45import org .bukkit .Material ;
6+ import org .bukkit .NamespacedKey ;
57import org .bukkit .World ;
68import org .bukkit .entity .Entity ;
79import org .bukkit .entity .Player ;
10+ import org .bukkit .plugin .Plugin ;
811
912import javax .annotation .Nonnull ;
13+ import javax .annotation .Nullable ;
1014import java .lang .reflect .Method ;
15+ import java .util .regex .Pattern ;
1116
1217/**
1318 * This class gives access to
@@ -21,7 +26,8 @@ public final class BukkitReflectionUtils {
2126
2227 protected static final ILogger logger = ILogger .forThisClass ();
2328
24- private BukkitReflectionUtils () {}
29+ private BukkitReflectionUtils () {
30+ }
2531
2632 public static double getAbsorptionAmount (@ Nonnull Player player ) {
2733 Class <?> classOfPlayer = player .getClass ();
@@ -75,8 +81,8 @@ public static int getMinHeight(@Nonnull World world) {
7581 }
7682
7783 /**
78- * @deprecated not implemented in all forks of bukkit
7984 * @return if the entity is in water, {@code false} otherwise or if not implemented
85+ * @deprecated not implemented in all forks of bukkit
8086 */
8187 @ Deprecated
8288 public static boolean isInWater (@ Nonnull Entity entity ) {
@@ -88,4 +94,80 @@ public static boolean isInWater(@Nonnull Entity entity) {
8894 return false ;
8995 }
9096
97+ private static final Pattern VALID_KEY = Pattern .compile ("[a-z0-9/._-]+" );
98+
99+ /**
100+ * Get a NamespacedKey from the supplied string.
101+ *
102+ * The default namespace will be Minecraft's (i.e.
103+ * {@link NamespacedKey#minecraft(String)}).
104+ *
105+ * @param key the key to convert to a NamespacedKey
106+ * @return the created NamespacedKey. null if invalid
107+ * @see #fromString(String, Plugin)
108+ */
109+ @ Nullable
110+ public static NamespacedKey fromString (@ Nonnull String key ) {
111+ return fromString (key , null );
112+ }
113+
114+ /**
115+ * Does not exists in versions prior to 1.14
116+ *
117+ * Get a NamespacedKey from the supplied string with a default namespace if
118+ * a namespace is not defined. This is a utility method meant to fetch a
119+ * NamespacedKey from user input. Please note that casing does matter and
120+ * any instance of uppercase characters will be considered invalid. The
121+ * input contract is as follows:
122+ * <pre>
123+ * fromString("foo", plugin) -{@literal >} "plugin:foo"
124+ * fromString("foo:bar", plugin) -{@literal >} "foo:bar"
125+ * fromString(":foo", null) -{@literal >} "minecraft:foo"
126+ * fromString("foo", null) -{@literal >} "minecraft:foo"
127+ * fromString("Foo", plugin) -{@literal >} null
128+ * fromString(":Foo", plugin) -{@literal >} null
129+ * fromString("foo:bar:bazz", plugin) -{@literal >} null
130+ * fromString("", plugin) -{@literal >} null
131+ * </pre>
132+ *
133+ * @param string the string to convert to a NamespacedKey
134+ * @param defaultNamespace the default namespace to use if none was
135+ * supplied. If null, the {@code minecraft} namespace
136+ * ({@link NamespacedKey#minecraft(String)}) will be used
137+ * @return the created NamespacedKey. null if invalid key
138+ * @see #fromString(String)
139+ */
140+ @ Nullable
141+ public static NamespacedKey fromString (@ Nonnull String string , @ Nullable Plugin defaultNamespace ) {
142+ Preconditions .checkArgument (string != null && !string .isEmpty (), "Input string must not be empty or null" );
143+
144+ String [] components = string .split (":" , 3 );
145+ if (components .length > 2 ) {
146+ return null ;
147+ }
148+
149+ String key = (components .length == 2 ) ? components [1 ] : "" ;
150+ if (components .length == 1 ) {
151+ String value = components [0 ];
152+ if (value .isEmpty () || !VALID_KEY .matcher (value ).matches ()) {
153+ return null ;
154+ }
155+
156+ return (defaultNamespace != null ) ? new NamespacedKey (defaultNamespace , value ) : NamespacedKey .minecraft (value );
157+ } else if (components .length == 2 && !VALID_KEY .matcher (key ).matches ()) {
158+ return null ;
159+ }
160+
161+ String namespace = components [0 ];
162+ if (namespace .isEmpty ()) {
163+ return (defaultNamespace != null ) ? new NamespacedKey (defaultNamespace , key ) : NamespacedKey .minecraft (key );
164+ }
165+
166+ if (!VALID_KEY .matcher (namespace ).matches ()) {
167+ return null ;
168+ }
169+
170+ return new NamespacedKey (namespace , key );
171+ }
172+
91173}
0 commit comments