package net.minecraftforge.common.property; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import net.minecraft.block.Block; import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; import com.google.common.base.Optional; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableTable; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; public class ExtendedBlockState extends BlockStateContainer { private final ImmutableSet> unlistedProperties; public ExtendedBlockState(Block blockIn, IProperty[] properties, IUnlistedProperty[] unlistedProperties) { super(blockIn, properties, buildUnlistedMap(unlistedProperties)); ImmutableSet.Builder> builder = ImmutableSet.builder(); for(IUnlistedProperty property : unlistedProperties) { builder.add(property); } this.unlistedProperties = builder.build(); } public Collection> getUnlistedProperties() { return unlistedProperties; } private static ImmutableMap, Optional> buildUnlistedMap(IUnlistedProperty[] unlistedProperties) { ImmutableMap.Builder, Optional> builder = ImmutableMap.builder(); for(IUnlistedProperty p : unlistedProperties) { builder.put(p, Optional.absent()); } return builder.build(); } @Override protected StateImplementation createState(Block block, ImmutableMap, Comparable> properties, ImmutableMap, Optional> unlistedProperties) { if (unlistedProperties == null || unlistedProperties.isEmpty()) return super.createState(block, properties, unlistedProperties); return new ExtendedStateImplementation(block, properties, unlistedProperties, null); } protected static class ExtendedStateImplementation extends StateImplementation implements IExtendedBlockState { private final ImmutableMap, Optional> unlistedProperties; private Map, Comparable>, BlockStateContainer.StateImplementation> normalMap; protected ExtendedStateImplementation(Block block, ImmutableMap, Comparable> properties, ImmutableMap, Optional> unlistedProperties, ImmutableTable, Comparable, IBlockState> table) { super(block, properties); this.unlistedProperties = unlistedProperties; this.propertyValueTable = table; } @Override public , V extends T> IBlockState withProperty(IProperty property, V value) { if (!this.getProperties().containsKey(property)) { throw new IllegalArgumentException("Cannot set property " + property + " as it does not exist in " + getBlock().getBlockState()); } else { if (!property.getAllowedValues().contains(value)) { throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on block " + Block.REGISTRY.getNameForObject(getBlock()) + ", it is not an allowed value"); } else { if (this.getProperties().get(property) == value) { return this; } Map, Comparable> map = Maps.newHashMap(getProperties()); map.put(property, value); if (Iterables.all(unlistedProperties.values(), Predicates.>equalTo(Optional.absent()))) { // no dynamic properties present, looking up in the normal table return normalMap.get(map); } ImmutableTable, Comparable, IBlockState> table = propertyValueTable; table = ((StateImplementation) table.get(property, value)).getPropertyValueTable(); return new ExtendedStateImplementation(getBlock(), ImmutableMap.copyOf(map), unlistedProperties, table).setMap(this.normalMap); } } } public IExtendedBlockState withProperty(IUnlistedProperty property, V value) { if(!this.unlistedProperties.containsKey(property)) { throw new IllegalArgumentException("Cannot set unlisted property " + property + " as it does not exist in " + getBlock().getBlockState()); } if(!property.isValid(value)) { throw new IllegalArgumentException("Cannot set unlisted property " + property + " to " + value + " on block " + Block.REGISTRY.getNameForObject(getBlock()) + ", it is not an allowed value"); } Map, Optional> newMap = new HashMap, Optional>(unlistedProperties); newMap.put(property, Optional.fromNullable(value)); if(Iterables.all(newMap.values(), Predicates.>equalTo(Optional.absent()))) { // no dynamic properties, lookup normal state return (IExtendedBlockState) normalMap.get(getProperties()); } return new ExtendedStateImplementation(getBlock(), getProperties(), ImmutableMap.copyOf(newMap), propertyValueTable).setMap(this.normalMap); } public Collection> getUnlistedNames() { return Collections.unmodifiableCollection(unlistedProperties.keySet()); } public V getValue(IUnlistedProperty property) { if(!this.unlistedProperties.containsKey(property)) { throw new IllegalArgumentException("Cannot get unlisted property " + property + " as it does not exist in " + getBlock().getBlockState()); } return property.getType().cast(this.unlistedProperties.get(property).orNull()); } public ImmutableMap, Optional> getUnlistedProperties() { return unlistedProperties; } @Override public void buildPropertyValueTable(Map, Comparable>, BlockStateContainer.StateImplementation> map) { this.normalMap = map; super.buildPropertyValueTable(map); } private ExtendedStateImplementation setMap(Map, Comparable>, BlockStateContainer.StateImplementation> map) { this.normalMap = map; return this; } public IBlockState getClean() { return this.normalMap.get(getProperties()); } } }