package net.minecraft.data.models.blockstates; import com.google.common.collect.Maps; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.Property; public interface Condition extends Supplier { void validate(StateDefinition stateDefinition); static Condition.TerminalCondition condition() { return new Condition.TerminalCondition(); } static Condition and(Condition... conditions) { return new Condition.CompositeCondition(Condition.Operation.AND, Arrays.asList(conditions)); } static Condition or(Condition... conditions) { return new Condition.CompositeCondition(Condition.Operation.OR, Arrays.asList(conditions)); } public static class CompositeCondition implements Condition { private final Condition.Operation operation; private final List subconditions; CompositeCondition(Condition.Operation operation, List subconditions) { this.operation = operation; this.subconditions = subconditions; } @Override public void validate(StateDefinition stateDefinition) { this.subconditions.forEach(condition -> condition.validate(stateDefinition)); } public JsonElement get() { JsonArray jsonArray = new JsonArray(); this.subconditions.stream().map(Supplier::get).forEach(jsonArray::add); JsonObject jsonObject = new JsonObject(); jsonObject.add(this.operation.id, jsonArray); return jsonObject; } } public static enum Operation { AND("AND"), OR("OR"); final String id; private Operation(final String id) { this.id = id; } } public static class TerminalCondition implements Condition { private final Map, String> terms = Maps., String>newHashMap(); private static > String joinValues(Property property, Stream valueStream) { return (String)valueStream.map(property::getName).collect(Collectors.joining("|")); } private static > String getTerm(Property property, T firstValue, T[] additionalValues) { return joinValues(property, Stream.concat(Stream.of(firstValue), Stream.of(additionalValues))); } private > void putValue(Property property, String value) { String string = (String)this.terms.put(property, value); if (string != null) { throw new IllegalStateException("Tried to replace " + property + " value from " + string + " to " + value); } } public final > Condition.TerminalCondition term(Property property, T value) { this.putValue(property, property.getName(value)); return this; } @SafeVarargs public final > Condition.TerminalCondition term(Property property, T firstValue, T... additionalValues) { this.putValue(property, getTerm(property, firstValue, additionalValues)); return this; } public final > Condition.TerminalCondition negatedTerm(Property property, T value) { this.putValue(property, "!" + property.getName(value)); return this; } @SafeVarargs public final > Condition.TerminalCondition negatedTerm(Property property, T firstValue, T... additionalValues) { this.putValue(property, "!" + getTerm(property, firstValue, additionalValues)); return this; } public JsonElement get() { JsonObject jsonObject = new JsonObject(); this.terms.forEach((property, string) -> jsonObject.addProperty(property.getName(), string)); return jsonObject; } @Override public void validate(StateDefinition stateDefinition) { List> list = (List>)this.terms .keySet() .stream() .filter(property -> stateDefinition.getProperty(property.getName()) != property) .collect(Collectors.toList()); if (!list.isEmpty()) { throw new IllegalStateException("Properties " + list + " are missing from " + stateDefinition); } } } }