KeyValueCondition.java

net.minecraft.client.renderer.block.dispatch.multipart.KeyValueCondition

信息

  • 全限定名:net.minecraft.client.renderer.block.dispatch.multipart.KeyValueCondition
  • 类型:public record
  • 包:net.minecraft.client.renderer.block.dispatch.multipart
  • 源码路径:src/main/java/net/minecraft/client/renderer/block/dispatch/multipart/KeyValueCondition.java
  • 起始行号:L25
  • 实现:Condition
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L26
    • 说明:

      TODO

  • CODEC

    • 类型: Codec<KeyValueCondition>
    • 修饰符: public static final
    • 源码定位: L27
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.renderer.block.dispatch.multipart.KeyValueCondition.Term

    • 类型: record
    • 修饰符: public
    • 源码定位: L47
    • 说明:

      TODO

  • net.minecraft.client.renderer.block.dispatch.multipart.KeyValueCondition.Terms

    • 类型: record
    • 修饰符: public
    • 源码定位: L70
    • 说明:

      TODO

构造器

方法

下面的方法块按源码顺序生成。

public <O,S extends StateHolder<O,S>> Predicate<S> instantiate(StateDefinition<O,S> definition) @ L30

  • 方法名:instantiate
  • 源码定位:L30
  • 返回类型:<O,S extends StateHolder<O,S>> Predicate
  • 修饰符:public

参数:

  • definition: StateDefinition<O,S>

说明:

TODO

private static <O,S extends StateHolder<O,S>> Predicate<S> instantiate(StateDefinition<O,S> definition, String key, KeyValueCondition.Terms valueTest) @ L37

  • 方法名:instantiate
  • 源码定位:L37
  • 返回类型:<O,S extends StateHolder<O,S>> Predicate
  • 修饰符:private static

参数:

  • definition: StateDefinition<O,S>
  • key: String
  • valueTest: KeyValueCondition.Terms

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public record KeyValueCondition(Map<String, KeyValueCondition.Terms> tests) implements Condition {
    private static final Logger LOGGER = LogUtils.getLogger();
    public static final Codec<KeyValueCondition> CODEC = ExtraCodecs.nonEmptyMap(Codec.unboundedMap(Codec.STRING, KeyValueCondition.Terms.CODEC))
        .xmap(KeyValueCondition::new, KeyValueCondition::tests);
 
    @Override
    public <O, S extends StateHolder<O, S>> Predicate<S> instantiate(StateDefinition<O, S> definition) {
        List<Predicate<S>> predicates = new ArrayList<>(this.tests.size());
        this.tests.forEach((key, valueTest) -> predicates.add(instantiate(definition, key, valueTest)));
        return Util.allOf(predicates);
    }
 
    private static <O, S extends StateHolder<O, S>> Predicate<S> instantiate(StateDefinition<O, S> definition, String key, KeyValueCondition.Terms valueTest) {
        Property<?> property = definition.getProperty(key);
        if (property == null) {
            throw new IllegalArgumentException(String.format(Locale.ROOT, "Unknown property '%s' on '%s'", key, definition.getOwner()));
        } else {
            return valueTest.instantiate(definition.getOwner(), property);
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public record Term(String value, boolean negated) {
        private static final String NEGATE = "!";
 
        public Term(String value, boolean negated) {
            if (value.isEmpty()) {
                throw new IllegalArgumentException("Empty term");
            } else {
                this.value = value;
                this.negated = negated;
            }
        }
 
        public static KeyValueCondition.Term parse(String value) {
            return value.startsWith("!") ? new KeyValueCondition.Term(value.substring(1), true) : new KeyValueCondition.Term(value, false);
        }
 
        @Override
        public String toString() {
            return this.negated ? "!" + this.value : this.value;
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public record Terms(List<KeyValueCondition.Term> entries) {
        private static final char SEPARATOR = '|';
        private static final Joiner JOINER = Joiner.on('|');
        private static final Splitter SPLITTER = Splitter.on('|');
        private static final Codec<String> LEGACY_REPRESENTATION_CODEC = Codec.either(Codec.INT, Codec.BOOL)
            .flatComapMap(either -> either.map(String::valueOf, String::valueOf), o -> DataResult.error(() -> "This codec can't be used for encoding"));
        public static final Codec<KeyValueCondition.Terms> CODEC = Codec.withAlternative(Codec.STRING, LEGACY_REPRESENTATION_CODEC)
            .comapFlatMap(KeyValueCondition.Terms::parse, KeyValueCondition.Terms::toString);
 
        public Terms(List<KeyValueCondition.Term> entries) {
            if (entries.isEmpty()) {
                throw new IllegalArgumentException("Empty value for property");
            } else {
                this.entries = entries;
            }
        }
 
        public static DataResult<KeyValueCondition.Terms> parse(String value) {
            List<KeyValueCondition.Term> terms = SPLITTER.splitToStream(value).map(KeyValueCondition.Term::parse).toList();
            if (terms.isEmpty()) {
                return DataResult.error(() -> "Empty value for property");
            } else {
                for (KeyValueCondition.Term entry : terms) {
                    if (entry.value.isEmpty()) {
                        return DataResult.error(() -> "Empty term in value '" + value + "'");
                    }
                }
 
                return DataResult.success(new KeyValueCondition.Terms(terms));
            }
        }
 
        @Override
        public String toString() {
            return JOINER.join(this.entries);
        }
 
        public <O, S extends StateHolder<O, S>, T extends Comparable<T>> Predicate<S> instantiate(O owner, Property<T> property) {
            Predicate<T> allowedValueTest = Util.anyOf(Lists.transform(this.entries, t -> this.instantiate(owner, property, t)));
            List<T> allowedValues = new ArrayList<>(property.getPossibleValues());
            int allValuesCount = allowedValues.size();
            allowedValues.removeIf(allowedValueTest.negate());
            int allowedValuesCount = allowedValues.size();
            if (allowedValuesCount == 0) {
                KeyValueCondition.LOGGER.warn("Condition {} for property {} on {} is always false", this, property.getName(), owner);
                return blockState -> false;
            } else {
                int rejectedValuesCount = allValuesCount - allowedValuesCount;
                if (rejectedValuesCount == 0) {
                    KeyValueCondition.LOGGER.warn("Condition {} for property {} on {} is always true", this, property.getName(), owner);
                    return blockState -> true;
                } else {
                    boolean negate;
                    List<T> valuesToMatch;
                    if (allowedValuesCount <= rejectedValuesCount) {
                        negate = false;
                        valuesToMatch = allowedValues;
                    } else {
                        negate = true;
                        List<T> rejectedValues = new ArrayList<>(property.getPossibleValues());
                        rejectedValues.removeIf(allowedValueTest);
                        valuesToMatch = rejectedValues;
                    }
 
                    if (valuesToMatch.size() == 1) {
                        T expectedValue = (T)valuesToMatch.getFirst();
                        return state -> {
                            T value = state.getValue(property);
                            return expectedValue.equals(value) ^ negate;
                        };
                    } else {
                        return state -> {
                            T value = state.getValue(property);
                            return valuesToMatch.contains(value) ^ negate;
                        };
                    }
                }
            }
        }
 
        private <T extends Comparable<T>> T getValueOrThrow(Object owner, Property<T> property, String input) {
            Optional<T> value = property.getValue(input);
            if (value.isEmpty()) {
                throw new RuntimeException(String.format(Locale.ROOT, "Unknown value '%s' for property '%s' on '%s' in '%s'", input, property, owner, this));
            } else {
                return value.get();
            }
        }
 
        private <T extends Comparable<T>> Predicate<T> instantiate(Object owner, Property<T> property, KeyValueCondition.Term term) {
            T parsedValue = this.getValueOrThrow(owner, property, term.value);
            return term.negated ? value -> !value.equals(parsedValue) : value -> value.equals(parsedValue);
        }
    }
}

引用的其他类

  • Condition

    • 引用位置: 实现
  • ExtraCodecs

    • 引用位置: 方法调用
    • 关联成员: ExtraCodecs.nonEmptyMap()
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.allOf(), Util.anyOf()
  • StateDefinition

    • 引用位置: 参数
  • StateHolder

    • 引用位置: 返回值