package net.minecraft.world.level.block.state; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Map.Entry; import java.util.function.Function; import java.util.stream.Collectors; import javax.annotation.Nullable; import net.minecraft.world.level.block.state.properties.Property; public abstract class StateHolder { public static final String NAME_TAG = "Name"; public static final String PROPERTIES_TAG = "Properties"; private static final Function, Comparable>, String> PROPERTY_ENTRY_TO_STRING_FUNCTION = new Function, Comparable>, String>() { public String apply(@Nullable Entry, Comparable> p_61155_) { if (p_61155_ == null) { return ""; } else { Property property = p_61155_.getKey(); return property.getName() + "=" + this.getName(property, p_61155_.getValue()); } } private > String getName(Property p_61152_, Comparable p_61153_) { return p_61152_.getName((T)p_61153_); } }; protected final O owner; private final Reference2ObjectArrayMap, Comparable> values; private Map, S[]> neighbours; protected final MapCodec propertiesCodec; protected StateHolder(O p_61117_, Reference2ObjectArrayMap, Comparable> p_331170_, MapCodec p_61119_) { this.owner = p_61117_; this.values = p_331170_; this.propertiesCodec = p_61119_; } public > S cycle(Property p_61123_) { return this.setValue(p_61123_, findNextInCollection(p_61123_.getPossibleValues(), this.getValue(p_61123_))); } protected static T findNextInCollection(List p_366325_, T p_61132_) { int i = p_366325_.indexOf(p_61132_) + 1; return i == p_366325_.size() ? p_366325_.getFirst() : p_366325_.get(i); } @Override public String toString() { StringBuilder stringbuilder = new StringBuilder(); stringbuilder.append(this.owner); if (!this.getValues().isEmpty()) { stringbuilder.append('['); stringbuilder.append(this.getValues().entrySet().stream().map(PROPERTY_ENTRY_TO_STRING_FUNCTION).collect(Collectors.joining(","))); stringbuilder.append(']'); } return stringbuilder.toString(); } @Override public final boolean equals(Object p_397228_) { return super.equals(p_397228_); } @Override public int hashCode() { return super.hashCode(); } public Collection> getProperties() { return Collections.unmodifiableCollection(this.values.keySet()); } public boolean hasProperty(Property p_61139_) { return this.values.containsKey(p_61139_); } public > T getValue(Property p_61144_) { Comparable comparable = this.values.get(p_61144_); if (comparable == null) { throw new IllegalArgumentException("Cannot get property " + p_61144_ + " as it does not exist in " + this.owner); } else { return p_61144_.getValueClass().cast(comparable); } } public > Optional getOptionalValue(Property p_61146_) { return Optional.ofNullable(this.getNullableValue(p_61146_)); } public > T getValueOrElse(Property p_364529_, T p_364048_) { return Objects.requireNonNullElse(this.getNullableValue(p_364529_), p_364048_); } @Nullable private > T getNullableValue(Property p_361815_) { Comparable comparable = this.values.get(p_361815_); return comparable == null ? null : p_361815_.getValueClass().cast(comparable); } public , V extends T> S setValue(Property p_61125_, V p_61126_) { Comparable comparable = this.values.get(p_61125_); if (comparable == null) { throw new IllegalArgumentException("Cannot set property " + p_61125_ + " as it does not exist in " + this.owner); } else { return this.setValueInternal(p_61125_, p_61126_, comparable); } } public , V extends T> S trySetValue(Property p_263324_, V p_263334_) { Comparable comparable = this.values.get(p_263324_); return (S)(comparable == null ? this : this.setValueInternal(p_263324_, p_263334_, comparable)); } private , V extends T> S setValueInternal(Property p_361946_, V p_367503_, Comparable p_369806_) { if (p_369806_.equals(p_367503_)) { return (S)this; } else { int i = p_361946_.getInternalIndex((T)p_367503_); if (i < 0) { throw new IllegalArgumentException( "Cannot set property " + p_361946_ + " to " + p_367503_ + " on " + this.owner + ", it is not an allowed value" ); } else { return (S)this.neighbours.get(p_361946_)[i]; } } } public void populateNeighbours(Map, Comparable>, S> p_61134_) { if (this.neighbours != null) { throw new IllegalStateException(); } else { Map, S[]> map = new Reference2ObjectArrayMap<>(this.values.size()); for (Entry, Comparable> entry : this.values.entrySet()) { Property property = entry.getKey(); map.put(property, (S[])property.getPossibleValues().stream().map(p_360554_ -> p_61134_.get(this.makeNeighbourValues(property, p_360554_))).toArray()); } this.neighbours = map; } } private Map, Comparable> makeNeighbourValues(Property p_61141_, Comparable p_61142_) { Map, Comparable> map = new Reference2ObjectArrayMap<>(this.values); map.put(p_61141_, p_61142_); return map; } public Map, Comparable> getValues() { return this.values; } protected static > Codec codec(Codec p_61128_, Function p_61129_) { return p_61128_.dispatch( "Name", p_61121_ -> p_61121_.owner, p_327407_ -> { S s = p_61129_.apply((O)p_327407_); return s.getValues().isEmpty() ? MapCodec.unit(s) : s.propertiesCodec.codec().lenientOptionalFieldOf("Properties").xmap(p_187544_ -> p_187544_.orElse(s), Optional::of); } ); } }