293 lines
9.5 KiB
Java
293 lines
9.5 KiB
Java
package net.minecraft.resources;
|
|
|
|
import com.mojang.brigadier.StringReader;
|
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
|
import com.mojang.serialization.Codec;
|
|
import com.mojang.serialization.DataResult;
|
|
import io.netty.buffer.ByteBuf;
|
|
import java.util.function.UnaryOperator;
|
|
import net.minecraft.ResourceLocationException;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.network.codec.ByteBufCodecs;
|
|
import net.minecraft.network.codec.StreamCodec;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
/**
|
|
* An immutable location of a resource, in terms of a path and namespace.
|
|
* <p>
|
|
* This is used as an identifier for a resource, usually for those housed in a {@link net.minecraft.core.Registry}, such as blocks and items.
|
|
* <p>
|
|
* {@code minecraft} is always taken as the default namespace for a resource location when none is explicitly stated. When using this for registering objects, this namespace <strong>should</strong> only be used for resources added by Minecraft itself.
|
|
* <p>
|
|
* Generally, and by the implementation of {@link #toString()}, the string representation of this class is expressed in the form {@code namespace:path}. The colon is also used as the default separator for parsing strings as a {@code ResourceLocation}.
|
|
* @see net.minecraft.resources.ResourceKey
|
|
*/
|
|
public final class ResourceLocation implements Comparable<ResourceLocation> {
|
|
public static final Codec<ResourceLocation> CODEC = Codec.STRING.<ResourceLocation>comapFlatMap(ResourceLocation::read, ResourceLocation::toString).stable();
|
|
public static final StreamCodec<ByteBuf, ResourceLocation> STREAM_CODEC = ByteBufCodecs.STRING_UTF8.map(ResourceLocation::parse, ResourceLocation::toString);
|
|
public static final SimpleCommandExceptionType ERROR_INVALID = new SimpleCommandExceptionType(Component.translatable("argument.id.invalid"));
|
|
public static final char NAMESPACE_SEPARATOR = ':';
|
|
public static final String DEFAULT_NAMESPACE = "minecraft";
|
|
public static final String REALMS_NAMESPACE = "realms";
|
|
private final String namespace;
|
|
private final String path;
|
|
|
|
private ResourceLocation(String namespace, String path) {
|
|
assert isValidNamespace(namespace);
|
|
|
|
assert isValidPath(path);
|
|
|
|
this.namespace = namespace;
|
|
this.path = path;
|
|
}
|
|
|
|
private static ResourceLocation createUntrusted(String namespace, String path) {
|
|
return new ResourceLocation(assertValidNamespace(namespace, path), assertValidPath(namespace, path));
|
|
}
|
|
|
|
public static ResourceLocation fromNamespaceAndPath(String namespace, String path) {
|
|
return createUntrusted(namespace, path);
|
|
}
|
|
|
|
public static ResourceLocation parse(String location) {
|
|
return bySeparator(location, ':');
|
|
}
|
|
|
|
public static ResourceLocation withDefaultNamespace(String location) {
|
|
return new ResourceLocation("minecraft", assertValidPath("minecraft", location));
|
|
}
|
|
|
|
/**
|
|
* Attempts to parse the specified {@code location} as a {@code ResourceLocation} by splitting it into a
|
|
* namespace and path by a colon.
|
|
* <p>
|
|
* If no colon is present in the {@code location}, the namespace defaults to {@code minecraft}, taking the {@code location} as the path.
|
|
* @return the parsed resource location; otherwise {@code null} if there is a non {@code [a-z0-9_.-]} character in the decomposed namespace or a non {@code [a-z0-9/._-]} character in the decomposed path
|
|
* @see #of(String, char)
|
|
*
|
|
* @param location the location string to try to parse as a {@code ResourceLocation}
|
|
*/
|
|
@Nullable
|
|
public static ResourceLocation tryParse(String location) {
|
|
return tryBySeparator(location, ':');
|
|
}
|
|
|
|
@Nullable
|
|
public static ResourceLocation tryBuild(String namespace, String path) {
|
|
return isValidNamespace(namespace) && isValidPath(path) ? new ResourceLocation(namespace, path) : null;
|
|
}
|
|
|
|
public static ResourceLocation bySeparator(String location, char seperator) {
|
|
int i = location.indexOf(seperator);
|
|
if (i >= 0) {
|
|
String string = location.substring(i + 1);
|
|
if (i != 0) {
|
|
String string2 = location.substring(0, i);
|
|
return createUntrusted(string2, string);
|
|
} else {
|
|
return withDefaultNamespace(string);
|
|
}
|
|
} else {
|
|
return withDefaultNamespace(location);
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
public static ResourceLocation tryBySeparator(String location, char seperator) {
|
|
int i = location.indexOf(seperator);
|
|
if (i >= 0) {
|
|
String string = location.substring(i + 1);
|
|
if (!isValidPath(string)) {
|
|
return null;
|
|
} else if (i != 0) {
|
|
String string2 = location.substring(0, i);
|
|
return isValidNamespace(string2) ? new ResourceLocation(string2, string) : null;
|
|
} else {
|
|
return new ResourceLocation("minecraft", string);
|
|
}
|
|
} else {
|
|
return isValidPath(location) ? new ResourceLocation("minecraft", location) : null;
|
|
}
|
|
}
|
|
|
|
public static DataResult<ResourceLocation> read(String location) {
|
|
try {
|
|
return DataResult.success(parse(location));
|
|
} catch (ResourceLocationException var2) {
|
|
return DataResult.error(() -> "Not a valid resource location: " + location + " " + var2.getMessage());
|
|
}
|
|
}
|
|
|
|
public String getPath() {
|
|
return this.path;
|
|
}
|
|
|
|
public String getNamespace() {
|
|
return this.namespace;
|
|
}
|
|
|
|
public ResourceLocation withPath(String path) {
|
|
return new ResourceLocation(this.namespace, assertValidPath(this.namespace, path));
|
|
}
|
|
|
|
public ResourceLocation withPath(UnaryOperator<String> pathOperator) {
|
|
return this.withPath((String)pathOperator.apply(this.path));
|
|
}
|
|
|
|
public ResourceLocation withPrefix(String pathPrefix) {
|
|
return this.withPath(pathPrefix + this.path);
|
|
}
|
|
|
|
public ResourceLocation withSuffix(String pathSuffix) {
|
|
return this.withPath(this.path + pathSuffix);
|
|
}
|
|
|
|
public String toString() {
|
|
return this.namespace + ":" + this.path;
|
|
}
|
|
|
|
public boolean equals(Object object) {
|
|
if (this == object) {
|
|
return true;
|
|
} else {
|
|
return !(object instanceof ResourceLocation resourceLocation)
|
|
? false
|
|
: this.namespace.equals(resourceLocation.namespace) && this.path.equals(resourceLocation.path);
|
|
}
|
|
}
|
|
|
|
public int hashCode() {
|
|
return 31 * this.namespace.hashCode() + this.path.hashCode();
|
|
}
|
|
|
|
public int compareTo(ResourceLocation other) {
|
|
int i = this.path.compareTo(other.path);
|
|
if (i == 0) {
|
|
i = this.namespace.compareTo(other.namespace);
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
public String toDebugFileName() {
|
|
return this.toString().replace('/', '_').replace(':', '_');
|
|
}
|
|
|
|
public String toLanguageKey() {
|
|
return this.namespace + "." + this.path;
|
|
}
|
|
|
|
public String toShortLanguageKey() {
|
|
return this.namespace.equals("minecraft") ? this.path : this.toLanguageKey();
|
|
}
|
|
|
|
public String toLanguageKey(String type) {
|
|
return type + "." + this.toLanguageKey();
|
|
}
|
|
|
|
public String toLanguageKey(String type, String key) {
|
|
return type + "." + this.toLanguageKey() + "." + key;
|
|
}
|
|
|
|
private static String readGreedy(StringReader reader) {
|
|
int i = reader.getCursor();
|
|
|
|
while (reader.canRead() && isAllowedInResourceLocation(reader.peek())) {
|
|
reader.skip();
|
|
}
|
|
|
|
return reader.getString().substring(i, reader.getCursor());
|
|
}
|
|
|
|
public static ResourceLocation read(StringReader reader) throws CommandSyntaxException {
|
|
int i = reader.getCursor();
|
|
String string = readGreedy(reader);
|
|
|
|
try {
|
|
return parse(string);
|
|
} catch (ResourceLocationException var4) {
|
|
reader.setCursor(i);
|
|
throw ERROR_INVALID.createWithContext(reader);
|
|
}
|
|
}
|
|
|
|
public static ResourceLocation readNonEmpty(StringReader reader) throws CommandSyntaxException {
|
|
int i = reader.getCursor();
|
|
String string = readGreedy(reader);
|
|
if (string.isEmpty()) {
|
|
throw ERROR_INVALID.createWithContext(reader);
|
|
} else {
|
|
try {
|
|
return parse(string);
|
|
} catch (ResourceLocationException var4) {
|
|
reader.setCursor(i);
|
|
throw ERROR_INVALID.createWithContext(reader);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static boolean isAllowedInResourceLocation(char character) {
|
|
return character >= '0' && character <= '9'
|
|
|| character >= 'a' && character <= 'z'
|
|
|| character == '_'
|
|
|| character == ':'
|
|
|| character == '/'
|
|
|| character == '.'
|
|
|| character == '-';
|
|
}
|
|
|
|
/**
|
|
* @return {@code true} if the specified {@code path} is valid: consists only of {@code [a-z0-9/._-]} characters
|
|
*/
|
|
public static boolean isValidPath(String path) {
|
|
for (int i = 0; i < path.length(); i++) {
|
|
if (!validPathChar(path.charAt(i))) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @return {@code true} if the specified {@code namespace} is valid: consists only of {@code [a-z0-9_.-]} characters
|
|
*/
|
|
public static boolean isValidNamespace(String namespace) {
|
|
for (int i = 0; i < namespace.length(); i++) {
|
|
if (!validNamespaceChar(namespace.charAt(i))) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static String assertValidNamespace(String namespace, String path) {
|
|
if (!isValidNamespace(namespace)) {
|
|
throw new ResourceLocationException("Non [a-z0-9_.-] character in namespace of location: " + namespace + ":" + path);
|
|
} else {
|
|
return namespace;
|
|
}
|
|
}
|
|
|
|
public static boolean validPathChar(char pathChar) {
|
|
return pathChar == '_' || pathChar == '-' || pathChar >= 'a' && pathChar <= 'z' || pathChar >= '0' && pathChar <= '9' || pathChar == '/' || pathChar == '.';
|
|
}
|
|
|
|
private static boolean validNamespaceChar(char namespaceChar) {
|
|
return namespaceChar == '_'
|
|
|| namespaceChar == '-'
|
|
|| namespaceChar >= 'a' && namespaceChar <= 'z'
|
|
|| namespaceChar >= '0' && namespaceChar <= '9'
|
|
|| namespaceChar == '.';
|
|
}
|
|
|
|
private static String assertValidPath(String namespace, String path) {
|
|
if (!isValidPath(path)) {
|
|
throw new ResourceLocationException("Non [a-z0-9/._-] character in path of location: " + namespace + ":" + path);
|
|
} else {
|
|
return path;
|
|
}
|
|
}
|
|
}
|