while some of these may of been true, they are extreme cases and cause a ton of noise to plugin developers. Use ApiStatus.Internal instead of Deprecated for actual internal API that continues to have use (internally). These do not help plugin developers if they bring moise noise than value.
274 lines
8.5 KiB
Java
274 lines
8.5 KiB
Java
package org.bukkit;
|
|
|
|
import com.google.common.base.Preconditions;
|
|
import java.util.Locale;
|
|
import java.util.UUID;
|
|
import org.bukkit.plugin.Plugin;
|
|
import org.jetbrains.annotations.ApiStatus;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
/**
|
|
* Represents a String based key which consists of two components - a namespace
|
|
* and a key.
|
|
*
|
|
* Namespaces may only contain lowercase alphanumeric characters, periods,
|
|
* underscores, and hyphens.
|
|
* <p>
|
|
* Keys may only contain lowercase alphanumeric characters, periods,
|
|
* underscores, hyphens, and forward slashes.
|
|
*
|
|
*/
|
|
public final class NamespacedKey implements net.kyori.adventure.key.Key { // Paper - implement Key
|
|
|
|
/**
|
|
* The namespace representing all inbuilt keys.
|
|
*/
|
|
public static final String MINECRAFT = "minecraft";
|
|
/**
|
|
* The namespace representing all keys generated by Bukkit for backwards
|
|
* compatibility measures.
|
|
*/
|
|
public static final String BUKKIT = "bukkit";
|
|
//
|
|
private final String namespace;
|
|
private final String key;
|
|
|
|
private static boolean isValidNamespaceChar(char c) {
|
|
return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-';
|
|
}
|
|
|
|
private static boolean isValidKeyChar(char c) {
|
|
return isValidNamespaceChar(c) || c == '/';
|
|
}
|
|
|
|
private static boolean isValidNamespace(String namespace) {
|
|
int len = namespace.length();
|
|
if (len == 0) {
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
if (!isValidNamespaceChar(namespace.charAt(i))) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static boolean isValidKey(String key) {
|
|
int len = key.length();
|
|
if (len == 0) {
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
if (!isValidKeyChar(key.charAt(i))) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Create a key in a specific namespace.
|
|
* <p>
|
|
* For most plugin related code, you should prefer using the
|
|
* {@link NamespacedKey#NamespacedKey(Plugin, String)} constructor.
|
|
*
|
|
* @param namespace namespace
|
|
* @param key key
|
|
* @see #NamespacedKey(Plugin, String)
|
|
*/
|
|
public NamespacedKey(@NotNull String namespace, @NotNull String key) {
|
|
Preconditions.checkArgument(namespace != null && isValidNamespace(namespace), "Invalid namespace. Must be [a-z0-9._-]: %s", namespace);
|
|
Preconditions.checkArgument(key != null && isValidKey(key), "Invalid key. Must be [a-z0-9/._-]: %s", key);
|
|
|
|
this.namespace = namespace;
|
|
this.key = key;
|
|
|
|
String string = toString();
|
|
Preconditions.checkArgument(string.length() < 256, "NamespacedKey must be less than 256 characters", string);
|
|
}
|
|
|
|
/**
|
|
* Create a key in the plugin's namespace.
|
|
* <p>
|
|
* Namespaces may only contain lowercase alphanumeric characters, periods,
|
|
* underscores, and hyphens.
|
|
* <p>
|
|
* Keys may only contain lowercase alphanumeric characters, periods,
|
|
* underscores, hyphens, and forward slashes.
|
|
*
|
|
* @param plugin the plugin to use for the namespace
|
|
* @param key the key to create
|
|
*/
|
|
public NamespacedKey(@NotNull Plugin plugin, @NotNull String key) {
|
|
Preconditions.checkArgument(plugin != null, "Plugin cannot be null");
|
|
Preconditions.checkArgument(key != null, "Key cannot be null");
|
|
|
|
this.namespace = plugin.getName().toLowerCase(Locale.ROOT);
|
|
this.key = key.toLowerCase(Locale.ROOT);
|
|
|
|
// Check validity after normalization
|
|
Preconditions.checkArgument(isValidNamespace(this.namespace), "Invalid namespace. Must be [a-z0-9._-]: %s", this.namespace);
|
|
Preconditions.checkArgument(isValidKey(this.key), "Invalid key. Must be [a-z0-9/._-]: %s", this.key);
|
|
|
|
String string = toString();
|
|
Preconditions.checkArgument(string.length() < 256, "NamespacedKey must be less than 256 characters (%s)", string);
|
|
}
|
|
|
|
@NotNull
|
|
public String getNamespace() {
|
|
return namespace;
|
|
}
|
|
|
|
@NotNull
|
|
public String getKey() {
|
|
return key;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
// Paper start
|
|
int result = this.namespace.hashCode();
|
|
result = (31 * result) + this.key.hashCode();
|
|
return result;
|
|
// Paper end
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (obj == null) {
|
|
return false;
|
|
}
|
|
// Paper start
|
|
if (!(obj instanceof net.kyori.adventure.key.Key key)) return false;
|
|
return this.namespace.equals(key.namespace()) && this.key.equals(key.value());
|
|
// Paper end
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return this.namespace + ":" + this.key;
|
|
}
|
|
|
|
/**
|
|
* Return a new random key in the {@link #BUKKIT} namespace.
|
|
*
|
|
* @return new key
|
|
* @deprecated should never be used by plugins, for internal use only!!
|
|
*/
|
|
@ApiStatus.Internal
|
|
@NotNull
|
|
@Deprecated(since = "1.20.5")
|
|
public static NamespacedKey randomKey() {
|
|
return new NamespacedKey(BUKKIT, UUID.randomUUID().toString());
|
|
}
|
|
|
|
/**
|
|
* Get a key in the Minecraft namespace.
|
|
*
|
|
* @param key the key to use
|
|
* @return new key in the Minecraft namespace
|
|
*/
|
|
@NotNull
|
|
public static NamespacedKey minecraft(@NotNull String key) {
|
|
return new NamespacedKey(MINECRAFT, key);
|
|
}
|
|
|
|
/**
|
|
* Get a NamespacedKey from the supplied string with a default namespace if
|
|
* a namespace is not defined. This is a utility method meant to fetch a
|
|
* NamespacedKey from user input. Please note that casing does matter and
|
|
* any instance of uppercase characters will be considered invalid. The
|
|
* input contract is as follows:
|
|
* <pre>
|
|
* fromString("foo", plugin) -{@literal >} "plugin:foo"
|
|
* fromString("foo:bar", plugin) -{@literal >} "foo:bar"
|
|
* fromString(":foo", null) -{@literal >} "minecraft:foo"
|
|
* fromString("foo", null) -{@literal >} "minecraft:foo"
|
|
* fromString("Foo", plugin) -{@literal >} null
|
|
* fromString(":Foo", plugin) -{@literal >} null
|
|
* fromString("foo:bar:bazz", plugin) -{@literal >} null
|
|
* fromString("", plugin) -{@literal >} null
|
|
* </pre>
|
|
*
|
|
* @param string the string to convert to a NamespacedKey
|
|
* @param defaultNamespace the default namespace to use if none was
|
|
* supplied. If null, the {@code minecraft} namespace
|
|
* ({@link #minecraft(String)}) will be used
|
|
* @return the created NamespacedKey. null if invalid key
|
|
* @see #fromString(String)
|
|
*/
|
|
@Nullable
|
|
public static NamespacedKey fromString(@NotNull String string, @Nullable Plugin defaultNamespace) {
|
|
Preconditions.checkArgument(string != null && !string.isEmpty(), "Input string must not be empty or null");
|
|
|
|
String[] components = string.split(":", 3);
|
|
if (components.length > 2) {
|
|
return null;
|
|
}
|
|
|
|
String key = (components.length == 2) ? components[1] : "";
|
|
if (components.length == 1) {
|
|
String value = components[0];
|
|
if (value.isEmpty() || !isValidKey(value)) {
|
|
return null;
|
|
}
|
|
|
|
return (defaultNamespace != null) ? new NamespacedKey(defaultNamespace, value) : minecraft(value);
|
|
} else if (components.length == 2 && !isValidKey(key)) {
|
|
return null;
|
|
}
|
|
|
|
String namespace = components[0];
|
|
if (namespace.isEmpty()) {
|
|
return (defaultNamespace != null) ? new NamespacedKey(defaultNamespace, key) : minecraft(key);
|
|
}
|
|
|
|
if (!isValidNamespace(namespace)) {
|
|
return null;
|
|
}
|
|
|
|
return new NamespacedKey(namespace, key);
|
|
}
|
|
|
|
/**
|
|
* Get a NamespacedKey from the supplied string.
|
|
*
|
|
* The default namespace will be Minecraft's (i.e.
|
|
* {@link #minecraft(String)}).
|
|
*
|
|
* @param key the key to convert to a NamespacedKey
|
|
* @return the created NamespacedKey. null if invalid
|
|
* @see #fromString(String, Plugin)
|
|
*/
|
|
@Nullable
|
|
public static NamespacedKey fromString(@NotNull String key) {
|
|
return fromString(key, null);
|
|
}
|
|
|
|
// Paper start
|
|
@NotNull
|
|
@Override
|
|
public String namespace() {
|
|
return this.getNamespace();
|
|
}
|
|
|
|
@NotNull
|
|
@Override
|
|
public String value() {
|
|
return this.getKey();
|
|
}
|
|
|
|
@NotNull
|
|
@Override
|
|
public String asString() {
|
|
return this.namespace + ':' + this.key;
|
|
}
|
|
// Paper end
|
|
}
|