package net.minecraft.core; import com.mojang.datafixers.util.Either; import java.util.Collection; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Stream; import net.minecraft.core.Holder.Reference.Type; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import org.jetbrains.annotations.Nullable; public interface Holder { T value(); boolean isBound(); boolean is(ResourceLocation location); boolean is(ResourceKey resourceKey); boolean is(Predicate> predicate); boolean is(TagKey tagKey); @Deprecated boolean is(Holder holder); Stream> tags(); Either, T> unwrap(); Optional> unwrapKey(); Holder.Kind kind(); boolean canSerializeIn(HolderOwner owner); default String getRegisteredName() { return (String)this.unwrapKey().map(resourceKey -> resourceKey.location().toString()).orElse("[unregistered]"); } static Holder direct(T value) { return new Holder.Direct<>(value); } public record Direct(T value) implements Holder { @Override public boolean isBound() { return true; } @Override public boolean is(ResourceLocation location) { return false; } @Override public boolean is(ResourceKey resourceKey) { return false; } @Override public boolean is(TagKey tagKey) { return false; } @Override public boolean is(Holder holder) { return this.value.equals(holder.value()); } @Override public boolean is(Predicate> predicate) { return false; } @Override public Either, T> unwrap() { return Either.right(this.value); } @Override public Optional> unwrapKey() { return Optional.empty(); } @Override public Holder.Kind kind() { return Holder.Kind.DIRECT; } public String toString() { return "Direct{" + this.value + "}"; } @Override public boolean canSerializeIn(HolderOwner owner) { return true; } @Override public Stream> tags() { return Stream.of(); } } public static enum Kind { REFERENCE, DIRECT; } public static class Reference implements Holder { private final HolderOwner owner; @Nullable private Set> tags; private final Type type; @Nullable private ResourceKey key; @Nullable private T value; protected Reference(Type type, HolderOwner owner, @Nullable ResourceKey key, @Nullable T value) { this.owner = owner; this.type = type; this.key = key; this.value = value; } public static Holder.Reference createStandAlone(HolderOwner owner, ResourceKey key) { return new Holder.Reference<>(Type.STAND_ALONE, owner, key, null); } @Deprecated public static Holder.Reference createIntrusive(HolderOwner owner, @Nullable T value) { return new Holder.Reference<>(Type.INTRUSIVE, owner, null, value); } public ResourceKey key() { if (this.key == null) { throw new IllegalStateException("Trying to access unbound value '" + this.value + "' from registry " + this.owner); } else { return this.key; } } @Override public T value() { if (this.value == null) { throw new IllegalStateException("Trying to access unbound value '" + this.key + "' from registry " + this.owner); } else { return this.value; } } @Override public boolean is(ResourceLocation location) { return this.key().location().equals(location); } @Override public boolean is(ResourceKey resourceKey) { return this.key() == resourceKey; } private Set> boundTags() { if (this.tags == null) { throw new IllegalStateException("Tags not bound"); } else { return this.tags; } } @Override public boolean is(TagKey tagKey) { return this.boundTags().contains(tagKey); } @Override public boolean is(Holder holder) { return holder.is(this.key()); } @Override public boolean is(Predicate> predicate) { return predicate.test(this.key()); } @Override public boolean canSerializeIn(HolderOwner owner) { return this.owner.canSerializeIn(owner); } @Override public Either, T> unwrap() { return Either.left(this.key()); } @Override public Optional> unwrapKey() { return Optional.of(this.key()); } @Override public Holder.Kind kind() { return Holder.Kind.REFERENCE; } @Override public boolean isBound() { return this.key != null && this.value != null; } void bindKey(ResourceKey key) { if (this.key != null && key != this.key) { throw new IllegalStateException("Can't change holder key: existing=" + this.key + ", new=" + key); } else { this.key = key; } } protected void bindValue(T value) { if (this.type == Type.INTRUSIVE && this.value != value) { throw new IllegalStateException("Can't change holder " + this.key + " value: existing=" + this.value + ", new=" + value); } else { this.value = value; } } void bindTags(Collection> tags) { this.tags = Set.copyOf(tags); } @Override public Stream> tags() { return this.boundTags().stream(); } public String toString() { return "Reference{" + this.key + "=" + this.value + "}"; } } }