2020-05-18 21:11:59 +02:00
|
|
|
package net.minestom.server.utils;
|
|
|
|
|
|
|
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
2020-10-18 18:27:57 +02:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
2020-05-18 21:11:59 +02:00
|
|
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Represents a namespaced ID
|
|
|
|
* https://minecraft.gamepedia.com/Namespaced_ID
|
|
|
|
*/
|
|
|
|
public class NamespaceID implements CharSequence {
|
|
|
|
private static final Int2ObjectOpenHashMap<NamespaceID> cache = new Int2ObjectOpenHashMap<>();
|
2020-10-18 18:27:57 +02:00
|
|
|
private static final String legalLetters = "[0123456789abcdefghijklmnopqrstuvwxyz_-]+";
|
2020-10-25 00:00:32 +02:00
|
|
|
private static final String legalPathLetters = "[0123456789abcdefghijklmnopqrstuvwxyz./_-]+";
|
2020-05-18 21:11:59 +02:00
|
|
|
|
|
|
|
private final String domain;
|
|
|
|
private final String path;
|
|
|
|
private final String full;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extracts the domain from the namespace ID. "minecraft:stone" would return "minecraft".
|
|
|
|
* If no ':' character is found, "minecraft" is returned.
|
2020-08-20 02:42:27 +02:00
|
|
|
*
|
2020-05-18 21:11:59 +02:00
|
|
|
* @param namespaceID
|
|
|
|
* @return the domain of the namespace ID
|
|
|
|
*/
|
|
|
|
public static String getDomain(String namespaceID) {
|
2020-08-20 02:42:27 +02:00
|
|
|
final int index = namespaceID.indexOf(':');
|
|
|
|
if (index < 0)
|
2020-05-18 21:11:59 +02:00
|
|
|
return "minecraft";
|
2020-10-22 12:55:53 +02:00
|
|
|
assert namespaceID.indexOf(':', index + 1) == -1 : "Namespace ID can only have at most one colon ':' (" + namespaceID + ")";
|
2020-05-18 21:11:59 +02:00
|
|
|
return namespaceID.substring(0, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extracts the path from the namespace ID. "minecraft:blocks/stone" would return "blocks/stone".
|
|
|
|
* If no ':' character is found, the <pre>namespaceID</pre> is returned.
|
2020-08-20 02:42:27 +02:00
|
|
|
*
|
2020-05-18 21:11:59 +02:00
|
|
|
* @param namespaceID
|
|
|
|
* @return the path of the namespace ID
|
|
|
|
*/
|
|
|
|
public static String getPath(String namespaceID) {
|
2020-08-20 02:42:27 +02:00
|
|
|
final int index = namespaceID.indexOf(':');
|
|
|
|
if (index < 0)
|
2020-05-18 21:11:59 +02:00
|
|
|
return namespaceID;
|
2020-10-22 12:55:53 +02:00
|
|
|
assert namespaceID.indexOf(':', index + 1) == -1 : "Namespace ID can only have at most one colon ':' (" + namespaceID + ")";
|
2020-08-20 02:42:27 +02:00
|
|
|
return namespaceID.substring(index + 1);
|
2020-05-18 21:11:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int hash(String domain, String path) {
|
|
|
|
return Objects.hash(domain, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static NamespaceID from(String domain, String path) {
|
2020-08-20 02:42:27 +02:00
|
|
|
final int hash = hash(domain, path);
|
2020-05-18 21:11:59 +02:00
|
|
|
return cache.computeIfAbsent(hash, _unused -> new NamespaceID(domain, path));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static NamespaceID from(String id) {
|
|
|
|
return from(getDomain(id), getPath(id));
|
|
|
|
}
|
|
|
|
|
|
|
|
private NamespaceID(String path) {
|
2020-08-20 02:42:27 +02:00
|
|
|
final int index = path.indexOf(':');
|
|
|
|
if (index < 0) {
|
2020-05-18 21:11:59 +02:00
|
|
|
this.domain = "minecraft";
|
|
|
|
this.path = path;
|
|
|
|
} else {
|
|
|
|
this.domain = path.substring(0, index);
|
2020-08-20 02:42:27 +02:00
|
|
|
this.path = path.substring(index + 1);
|
2020-05-18 21:11:59 +02:00
|
|
|
}
|
|
|
|
this.full = toString();
|
2020-10-18 18:27:57 +02:00
|
|
|
validate();
|
2020-05-18 21:11:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private NamespaceID(String domain, String path) {
|
|
|
|
this.domain = domain;
|
|
|
|
this.path = path;
|
|
|
|
this.full = toString();
|
2020-10-18 18:27:57 +02:00
|
|
|
validate();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void validate() {
|
2020-10-22 12:55:53 +02:00
|
|
|
assert !domain.contains(".") && !domain.contains("/") : "Domain cannot contain a dot nor a slash character (" + full + ")";
|
|
|
|
assert domain.matches(legalLetters) : "Illegal character in domain (" + full + "). Must match " + legalLetters;
|
2020-10-25 00:00:32 +02:00
|
|
|
assert path.matches(legalPathLetters) : "Illegal character in path (" + full + "). Must match " + legalPathLetters;
|
2020-05-18 21:11:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public String getDomain() {
|
|
|
|
return domain;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getPath() {
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
if (this == o) return true;
|
|
|
|
if (o == null || getClass() != o.getClass()) return false;
|
|
|
|
NamespaceID that = (NamespaceID) o;
|
|
|
|
return Objects.equals(domain, that.domain) &&
|
|
|
|
Objects.equals(path, that.path);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
return hash(domain, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int length() {
|
|
|
|
return full.length();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public char charAt(int index) {
|
|
|
|
return full.charAt(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public CharSequence subSequence(int start, int end) {
|
|
|
|
return full.subSequence(start, end);
|
|
|
|
}
|
|
|
|
|
2020-10-18 18:27:57 +02:00
|
|
|
@NotNull
|
2020-05-18 21:11:59 +02:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
2020-08-20 02:42:27 +02:00
|
|
|
return domain + ":" + path;
|
2020-05-18 21:11:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|