minecraft-src/net/minecraft/world/level/block/state/properties/Property.java
2025-07-04 02:49:36 +03:00

117 lines
3.3 KiB
Java

package net.minecraft.world.level.block.state.properties;
import com.google.common.base.MoreObjects;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import net.minecraft.world.level.block.state.StateHolder;
import org.jetbrains.annotations.Nullable;
public abstract class Property<T extends Comparable<T>> {
private final Class<T> clazz;
private final String name;
@Nullable
private Integer hashCode;
private final Codec<T> codec = Codec.STRING
.comapFlatMap(
string -> (DataResult)this.getValue(string)
.map(DataResult::success)
.orElseGet(() -> DataResult.error(() -> "Unable to read property: " + this + " with value: " + string)),
this::getName
);
private final Codec<Property.Value<T>> valueCodec = this.codec.xmap(this::value, Property.Value::value);
protected Property(String name, Class<T> clazz) {
this.clazz = clazz;
this.name = name;
}
public Property.Value<T> value(T value) {
return new Property.Value<>(this, value);
}
public Property.Value<T> value(StateHolder<?, ?> holder) {
return new Property.Value<>(this, holder.getValue(this));
}
public Stream<Property.Value<T>> getAllValues() {
return this.getPossibleValues().stream().map(this::value);
}
public Codec<T> codec() {
return this.codec;
}
public Codec<Property.Value<T>> valueCodec() {
return this.valueCodec;
}
public String getName() {
return this.name;
}
/**
* @return the class of the values of this property
*/
public Class<T> getValueClass() {
return this.clazz;
}
public abstract List<T> getPossibleValues();
/**
* @return the name for the given value.
*/
public abstract String getName(T value);
public abstract Optional<T> getValue(String value);
public abstract int getInternalIndex(T value);
public String toString() {
return MoreObjects.toStringHelper(this).add("name", this.name).add("clazz", this.clazz).add("values", this.getPossibleValues()).toString();
}
public boolean equals(Object object) {
if (this == object) {
return true;
} else {
return !(object instanceof Property<?> property) ? false : this.clazz.equals(property.clazz) && this.name.equals(property.name);
}
}
public final int hashCode() {
if (this.hashCode == null) {
this.hashCode = this.generateHashCode();
}
return this.hashCode;
}
public int generateHashCode() {
return 31 * this.clazz.hashCode() + this.name.hashCode();
}
public <U, S extends StateHolder<?, S>> DataResult<S> parseValue(DynamicOps<U> ops, S stateHolder, U unparsedValue) {
DataResult<T> dataResult = this.codec.parse(ops, unparsedValue);
return dataResult.map(comparable -> stateHolder.setValue(this, comparable)).setPartial(stateHolder);
}
public record Value<T extends Comparable<T>>(Property<T> property, T value) {
public Value(Property<T> property, T value) {
if (!property.getPossibleValues().contains(value)) {
throw new IllegalArgumentException("Value " + value + " does not belong to property " + property);
} else {
this.property = property;
this.value = value;
}
}
public String toString() {
return this.property.getName() + "=" + this.property.getName(this.value);
}
}
}