minecraft-src/net/minecraft/world/level/block/state/StateDefinition.java
2025-07-04 01:41:11 +03:00

165 lines
6 KiB
Java

package net.minecraft.world.level.block.state;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Decoder;
import com.mojang.serialization.Encoder;
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.Map.Entry;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minecraft.world.level.block.state.properties.Property;
import org.jetbrains.annotations.Nullable;
public class StateDefinition<O, S extends StateHolder<O, S>> {
static final Pattern NAME_PATTERN = Pattern.compile("^[a-z0-9_]+$");
private final O owner;
private final ImmutableSortedMap<String, Property<?>> propertiesByName;
private final ImmutableList<S> states;
protected StateDefinition(Function<O, S> stateValueFunction, O owner, StateDefinition.Factory<O, S> valueFunction, Map<String, Property<?>> propertiesByName) {
this.owner = owner;
this.propertiesByName = ImmutableSortedMap.copyOf(propertiesByName);
Supplier<S> supplier = () -> (StateHolder)stateValueFunction.apply(owner);
MapCodec<S> mapCodec = MapCodec.of(Encoder.empty(), Decoder.unit(supplier));
for (Entry<String, Property<?>> entry : this.propertiesByName.entrySet()) {
mapCodec = appendPropertyCodec(mapCodec, supplier, (String)entry.getKey(), (Property)entry.getValue());
}
MapCodec<S> mapCodec2 = mapCodec;
Map<Map<Property<?>, Comparable<?>>, S> map = Maps.<Map<Property<?>, Comparable<?>>, S>newLinkedHashMap();
List<S> list = Lists.<S>newArrayList();
Stream<List<Pair<Property<?>, Comparable<?>>>> stream = Stream.of(Collections.emptyList());
for (Property<?> property : this.propertiesByName.values()) {
stream = stream.flatMap(listx -> property.getPossibleValues().stream().map(comparable -> {
List<Pair<Property<?>, Comparable<?>>> list2 = Lists.<Pair<Property<?>, Comparable<?>>>newArrayList(listx);
list2.add(Pair.of(property, comparable));
return list2;
}));
}
stream.forEach(list2 -> {
Reference2ObjectArrayMap<Property<?>, Comparable<?>> reference2ObjectArrayMap = new Reference2ObjectArrayMap<>(list2.size());
for (Pair<Property<?>, Comparable<?>> pair : list2) {
reference2ObjectArrayMap.put(pair.getFirst(), pair.getSecond());
}
S stateHolderx = valueFunction.create(owner, reference2ObjectArrayMap, mapCodec2);
map.put(reference2ObjectArrayMap, stateHolderx);
list.add(stateHolderx);
});
for (S stateHolder : list) {
stateHolder.populateNeighbours(map);
}
this.states = ImmutableList.copyOf(list);
}
private static <S extends StateHolder<?, S>, T extends Comparable<T>> MapCodec<S> appendPropertyCodec(
MapCodec<S> propertyCodec, Supplier<S> holderSupplier, String value, Property<T> property
) {
return Codec.mapPair(
propertyCodec,
property.valueCodec().fieldOf(value).orElseGet((Consumer<String>)(string -> {}), () -> property.value((StateHolder<?, ?>)holderSupplier.get()))
)
.xmap(
pair -> (StateHolder)((StateHolder)pair.getFirst()).setValue(property, ((Property.Value)pair.getSecond()).value()),
stateHolder -> Pair.of(stateHolder, property.value(stateHolder))
);
}
public ImmutableList<S> getPossibleStates() {
return this.states;
}
public S any() {
return (S)this.states.get(0);
}
public O getOwner() {
return this.owner;
}
public Collection<Property<?>> getProperties() {
return this.propertiesByName.values();
}
public String toString() {
return MoreObjects.toStringHelper(this)
.add("block", this.owner)
.add("properties", this.propertiesByName.values().stream().map(Property::getName).collect(Collectors.toList()))
.toString();
}
@Nullable
public Property<?> getProperty(String propertyName) {
return this.propertiesByName.get(propertyName);
}
public static class Builder<O, S extends StateHolder<O, S>> {
private final O owner;
private final Map<String, Property<?>> properties = Maps.<String, Property<?>>newHashMap();
public Builder(O owner) {
this.owner = owner;
}
public StateDefinition.Builder<O, S> add(Property<?>... properties) {
for (Property<?> property : properties) {
this.validateProperty(property);
this.properties.put(property.getName(), property);
}
return this;
}
private <T extends Comparable<T>> void validateProperty(Property<T> property) {
String string = property.getName();
if (!StateDefinition.NAME_PATTERN.matcher(string).matches()) {
throw new IllegalArgumentException(this.owner + " has invalidly named property: " + string);
} else {
Collection<T> collection = property.getPossibleValues();
if (collection.size() <= 1) {
throw new IllegalArgumentException(this.owner + " attempted use property " + string + " with <= 1 possible values");
} else {
for (T comparable : collection) {
String string2 = property.getName(comparable);
if (!StateDefinition.NAME_PATTERN.matcher(string2).matches()) {
throw new IllegalArgumentException(this.owner + " has property: " + string + " with invalidly named value: " + string2);
}
}
if (this.properties.containsKey(string)) {
throw new IllegalArgumentException(this.owner + " has duplicate property: " + string);
}
}
}
}
public StateDefinition<O, S> create(Function<O, S> stateValueFunction, StateDefinition.Factory<O, S> stateFunction) {
return new StateDefinition<>(stateValueFunction, this.owner, stateFunction, this.properties);
}
}
public interface Factory<O, S> {
S create(O object, Reference2ObjectArrayMap<Property<?>, Comparable<?>> reference2ObjectArrayMap, MapCodec<S> mapCodec);
}
}