package net.minecraft.resources;
import com.google.common.collect.MapMaker;
import com.mojang.serialization.Codec;
import io.netty.buffer.ByteBuf;
import java.util.Optional;
import java.util.concurrent.ConcurrentMap;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.codec.StreamCodec;
/**
* An immutable key for a resource, in terms of the name of its parent registry and its location in that registry.
*
* {@link net.minecraft.core.Registry} uses this to return resource keys for registry objects via {@link net.minecraft.core.Registry#getResourceKey(Object)}. It also uses this class to store its name, with the parent registry name set to {@code minecraft:root}. When used in this way it is usually referred to as a "registry key".
*
* @param The type of the resource represented by this {@code ResourceKey}, or the type of the registry if it is a registry key.
* @see net.minecraft.resources.ResourceLocation
*/
public class ResourceKey {
private static final ConcurrentMap> VALUES = new MapMaker().weakValues().makeMap();
/**
* The name of the parent registry of the resource.
*/
private final ResourceLocation registryName;
/**
* The location of the resource within the registry.
*/
private final ResourceLocation location;
public static Codec> codec(ResourceKey extends Registry> registryKey) {
return ResourceLocation.CODEC.xmap(resourceLocation -> create(registryKey, resourceLocation), ResourceKey::location);
}
public static StreamCodec> streamCodec(ResourceKey extends Registry> registryKey) {
return ResourceLocation.STREAM_CODEC.map(resourceLocation -> create(registryKey, resourceLocation), ResourceKey::location);
}
/**
* Constructs a new {@code ResourceKey} for a resource with the specified {@code location} within the registry specified by the given {@code registryKey}.
*
* @return the created resource key. The registry name is set to the location of the specified {@code registryKey} and with the specified {@code location} as the location of the resource.
*/
public static ResourceKey create(ResourceKey extends Registry> registryKey, ResourceLocation location) {
return create(registryKey.location, location);
}
/**
* @return the created registry key. The registry name is set to {@code minecraft:root} and the location the specified {@code registryName}.
*/
public static ResourceKey> createRegistryKey(ResourceLocation location) {
return create(Registries.ROOT_REGISTRY_NAME, location);
}
private static ResourceKey create(ResourceLocation registryName, ResourceLocation location) {
return (ResourceKey)VALUES.computeIfAbsent(
new ResourceKey.InternKey(registryName, location), internKey -> new ResourceKey(internKey.registry, internKey.location)
);
}
private ResourceKey(ResourceLocation registryName, ResourceLocation location) {
this.registryName = registryName;
this.location = location;
}
public String toString() {
return "ResourceKey[" + this.registryName + " / " + this.location + "]";
}
/**
* @return {@code true} if this resource key is a direct child of the specified {@code registryKey}.
*/
public boolean isFor(ResourceKey extends Registry>> registryKey) {
return this.registryName.equals(registryKey.location());
}
public Optional> cast(ResourceKey extends Registry> registryKey) {
return this.isFor(registryKey) ? Optional.of(this) : Optional.empty();
}
public ResourceLocation location() {
return this.location;
}
public ResourceLocation registry() {
return this.registryName;
}
public ResourceKey> registryKey() {
return createRegistryKey(this.registryName);
}
record InternKey(ResourceLocation registry, ResourceLocation location) {
}
}