minecraft-src/net/minecraft/advancements/critereon/StatePropertiesPredicate.java
2025-07-04 01:41:11 +03:00

195 lines
8.3 KiB
Java

package net.minecraft.advancements.critereon;
import com.google.common.collect.ImmutableList;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.netty.buffer.ByteBuf;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.StateHolder;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.material.FluidState;
public record StatePropertiesPredicate(List<StatePropertiesPredicate.PropertyMatcher> properties) {
private static final Codec<List<StatePropertiesPredicate.PropertyMatcher>> PROPERTIES_CODEC = Codec.unboundedMap(
Codec.STRING, StatePropertiesPredicate.ValueMatcher.CODEC
)
.xmap(
map -> map.entrySet()
.stream()
.map(entry -> new StatePropertiesPredicate.PropertyMatcher((String)entry.getKey(), (StatePropertiesPredicate.ValueMatcher)entry.getValue()))
.toList(),
list -> (Map)list.stream().collect(Collectors.toMap(StatePropertiesPredicate.PropertyMatcher::name, StatePropertiesPredicate.PropertyMatcher::valueMatcher))
);
public static final Codec<StatePropertiesPredicate> CODEC = PROPERTIES_CODEC.xmap(StatePropertiesPredicate::new, StatePropertiesPredicate::properties);
public static final StreamCodec<ByteBuf, StatePropertiesPredicate> STREAM_CODEC = StatePropertiesPredicate.PropertyMatcher.STREAM_CODEC
.apply(ByteBufCodecs.list())
.map(StatePropertiesPredicate::new, StatePropertiesPredicate::properties);
public <S extends StateHolder<?, S>> boolean matches(StateDefinition<?, S> properties, S targetProperty) {
for (StatePropertiesPredicate.PropertyMatcher propertyMatcher : this.properties) {
if (!propertyMatcher.match(properties, targetProperty)) {
return false;
}
}
return true;
}
public boolean matches(BlockState state) {
return this.matches(state.getBlock().getStateDefinition(), state);
}
public boolean matches(FluidState state) {
return this.matches(state.getType().getStateDefinition(), state);
}
public Optional<String> checkState(StateDefinition<?, ?> state) {
for (StatePropertiesPredicate.PropertyMatcher propertyMatcher : this.properties) {
Optional<String> optional = propertyMatcher.checkState(state);
if (optional.isPresent()) {
return optional;
}
}
return Optional.empty();
}
public static class Builder {
private final ImmutableList.Builder<StatePropertiesPredicate.PropertyMatcher> matchers = ImmutableList.builder();
private Builder() {
}
public static StatePropertiesPredicate.Builder properties() {
return new StatePropertiesPredicate.Builder();
}
public StatePropertiesPredicate.Builder hasProperty(Property<?> property, String value) {
this.matchers.add(new StatePropertiesPredicate.PropertyMatcher(property.getName(), new StatePropertiesPredicate.ExactMatcher(value)));
return this;
}
public StatePropertiesPredicate.Builder hasProperty(Property<Integer> property, int value) {
return this.hasProperty(property, Integer.toString(value));
}
public StatePropertiesPredicate.Builder hasProperty(Property<Boolean> property, boolean value) {
return this.hasProperty(property, Boolean.toString(value));
}
public <T extends Comparable<T> & StringRepresentable> StatePropertiesPredicate.Builder hasProperty(Property<T> property, T value) {
return this.hasProperty(property, value.getSerializedName());
}
public Optional<StatePropertiesPredicate> build() {
return Optional.of(new StatePropertiesPredicate(this.matchers.build()));
}
}
record ExactMatcher(String value) implements StatePropertiesPredicate.ValueMatcher {
public static final Codec<StatePropertiesPredicate.ExactMatcher> CODEC = Codec.STRING
.xmap(StatePropertiesPredicate.ExactMatcher::new, StatePropertiesPredicate.ExactMatcher::value);
public static final StreamCodec<ByteBuf, StatePropertiesPredicate.ExactMatcher> STREAM_CODEC = ByteBufCodecs.STRING_UTF8
.map(StatePropertiesPredicate.ExactMatcher::new, StatePropertiesPredicate.ExactMatcher::value);
@Override
public <T extends Comparable<T>> boolean match(StateHolder<?, ?> stateHolder, Property<T> property) {
T comparable = stateHolder.getValue(property);
Optional<T> optional = property.getValue(this.value);
return optional.isPresent() && comparable.compareTo((Comparable)optional.get()) == 0;
}
}
record PropertyMatcher(String name, StatePropertiesPredicate.ValueMatcher valueMatcher) {
public static final StreamCodec<ByteBuf, StatePropertiesPredicate.PropertyMatcher> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.STRING_UTF8,
StatePropertiesPredicate.PropertyMatcher::name,
StatePropertiesPredicate.ValueMatcher.STREAM_CODEC,
StatePropertiesPredicate.PropertyMatcher::valueMatcher,
StatePropertiesPredicate.PropertyMatcher::new
);
public <S extends StateHolder<?, S>> boolean match(StateDefinition<?, S> properties, S propertyToMatch) {
Property<?> property = properties.getProperty(this.name);
return property != null && this.valueMatcher.match(propertyToMatch, property);
}
public Optional<String> checkState(StateDefinition<?, ?> state) {
Property<?> property = state.getProperty(this.name);
return property != null ? Optional.empty() : Optional.of(this.name);
}
}
record RangedMatcher(Optional<String> minValue, Optional<String> maxValue) implements StatePropertiesPredicate.ValueMatcher {
public static final Codec<StatePropertiesPredicate.RangedMatcher> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
Codec.STRING.optionalFieldOf("min").forGetter(StatePropertiesPredicate.RangedMatcher::minValue),
Codec.STRING.optionalFieldOf("max").forGetter(StatePropertiesPredicate.RangedMatcher::maxValue)
)
.apply(instance, StatePropertiesPredicate.RangedMatcher::new)
);
public static final StreamCodec<ByteBuf, StatePropertiesPredicate.RangedMatcher> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.optional(ByteBufCodecs.STRING_UTF8),
StatePropertiesPredicate.RangedMatcher::minValue,
ByteBufCodecs.optional(ByteBufCodecs.STRING_UTF8),
StatePropertiesPredicate.RangedMatcher::maxValue,
StatePropertiesPredicate.RangedMatcher::new
);
@Override
public <T extends Comparable<T>> boolean match(StateHolder<?, ?> stateHolder, Property<T> property) {
T comparable = stateHolder.getValue(property);
if (this.minValue.isPresent()) {
Optional<T> optional = property.getValue((String)this.minValue.get());
if (optional.isEmpty() || comparable.compareTo((Comparable)optional.get()) < 0) {
return false;
}
}
if (this.maxValue.isPresent()) {
Optional<T> optional = property.getValue((String)this.maxValue.get());
if (optional.isEmpty() || comparable.compareTo((Comparable)optional.get()) > 0) {
return false;
}
}
return true;
}
}
interface ValueMatcher {
Codec<StatePropertiesPredicate.ValueMatcher> CODEC = Codec.either(StatePropertiesPredicate.ExactMatcher.CODEC, StatePropertiesPredicate.RangedMatcher.CODEC)
.xmap(Either::unwrap, valueMatcher -> {
if (valueMatcher instanceof StatePropertiesPredicate.ExactMatcher exactMatcher) {
return Either.left(exactMatcher);
} else if (valueMatcher instanceof StatePropertiesPredicate.RangedMatcher rangedMatcher) {
return Either.right(rangedMatcher);
} else {
throw new UnsupportedOperationException();
}
});
StreamCodec<ByteBuf, StatePropertiesPredicate.ValueMatcher> STREAM_CODEC = ByteBufCodecs.either(
StatePropertiesPredicate.ExactMatcher.STREAM_CODEC, StatePropertiesPredicate.RangedMatcher.STREAM_CODEC
)
.map(Either::unwrap, valueMatcher -> {
if (valueMatcher instanceof StatePropertiesPredicate.ExactMatcher exactMatcher) {
return Either.left(exactMatcher);
} else if (valueMatcher instanceof StatePropertiesPredicate.RangedMatcher rangedMatcher) {
return Either.right(rangedMatcher);
} else {
throw new UnsupportedOperationException();
}
});
<T extends Comparable<T>> boolean match(StateHolder<?, ?> stateHolder, Property<T> property);
}
}