001/* 002 * This file is part of Baritone. 003 * 004 * Baritone is free software: you can redistribute it and/or modify 005 * it under the terms of the GNU Lesser General Public License as published by 006 * the Free Software Foundation, either version 3 of the License, or 007 * (at your option) any later version. 008 * 009 * Baritone is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public License 015 * along with Baritone. If not, see <https://www.gnu.org/licenses/>. 016 */ 017 018package baritone.api.schematic; 019 020import net.minecraft.block.Block; 021import net.minecraft.block.BlockAir; 022import net.minecraft.block.properties.IProperty; 023import net.minecraft.block.state.IBlockState; 024import net.minecraft.init.Blocks; 025import java.util.Collection; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029 030public class SubstituteSchematic extends AbstractSchematic { 031 032 private final ISchematic schematic; 033 private final Map<Block, List<Block>> substitutions; 034 private final Map<IBlockState, Map<Block, IBlockState>> blockStateCache = new HashMap<>(); 035 036 public SubstituteSchematic(ISchematic schematic, Map<Block,List<Block>> substitutions) { 037 super(schematic.widthX(), schematic.heightY(), schematic.lengthZ()); 038 this.schematic = schematic; 039 this.substitutions = substitutions; 040 } 041 042 @Override 043 public boolean inSchematic(int x, int y, int z, IBlockState currentState) { 044 return schematic.inSchematic(x, y, z, currentState); 045 } 046 047 @Override 048 public IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable) { 049 IBlockState desired = schematic.desiredState(x, y, z, current, approxPlaceable); 050 Block desiredBlock = desired.getBlock(); 051 if (!substitutions.containsKey(desiredBlock)) { 052 return desired; 053 } 054 List<Block> substitutes = substitutions.get(desiredBlock); 055 if (substitutes.contains(current.getBlock()) && !(current.getBlock() instanceof BlockAir)) {// don't preserve air, it's almost always there and almost never wanted 056 return withBlock(desired, current.getBlock()); 057 } 058 for (Block substitute : substitutes) { 059 if (substitute instanceof BlockAir) { 060 return current.getBlock() instanceof BlockAir ? current : Blocks.AIR.getDefaultState(); // can always "place" air 061 } 062 for (IBlockState placeable : approxPlaceable) { 063 if (substitute.equals(placeable.getBlock())) { 064 return withBlock(desired, placeable.getBlock()); 065 } 066 } 067 } 068 return substitutes.get(0).getDefaultState(); 069 } 070 071 private IBlockState withBlock(IBlockState state, Block block) { 072 if (blockStateCache.containsKey(state) && blockStateCache.get(state).containsKey(block)) { 073 return blockStateCache.get(state).get(block); 074 } 075 Collection<IProperty<?>> properties = state.getPropertyKeys(); 076 IBlockState newState = block.getDefaultState(); 077 for (IProperty<?> property : properties) { 078 try { 079 newState = copySingleProp(state, newState, property); 080 } catch (IllegalArgumentException e) { //property does not exist for target block 081 } 082 } 083 blockStateCache.computeIfAbsent(state, s -> new HashMap<Block,IBlockState>()).put(block, newState); 084 return newState; 085 } 086 private <T extends Comparable<T>> IBlockState copySingleProp(IBlockState fromState, IBlockState toState, IProperty<T> prop) { 087 return toState.withProperty(prop, fromState.getValue(prop)); 088 } 089}