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.world.level.block.state.BlockState; 021import net.minecraft.world.level.block.Rotation; 022 023import java.util.List; 024import java.util.stream.Collectors; 025 026public class RotatedSchematic implements ISchematic { 027 028 private final ISchematic schematic; 029 private final Rotation rotation; 030 private final Rotation inverseRotation; 031 032 public RotatedSchematic(ISchematic schematic, Rotation rotation) { 033 this.schematic = schematic; 034 this.rotation = rotation; 035 // I don't think a 14 line switch would improve readability 036 this.inverseRotation = rotation.getRotated(rotation).getRotated(rotation); 037 } 038 039 @Override 040 public boolean inSchematic(int x, int y, int z, BlockState currentState) { 041 return schematic.inSchematic( 042 rotateX(x, z, widthX(), lengthZ(), inverseRotation), 043 y, 044 rotateZ(x, z, widthX(), lengthZ(), inverseRotation), 045 rotate(currentState, inverseRotation) 046 ); 047 } 048 049 @Override 050 public BlockState desiredState(int x, int y, int z, BlockState current, List<BlockState> approxPlaceable) { 051 return rotate(schematic.desiredState( 052 rotateX(x, z, widthX(), lengthZ(), inverseRotation), 053 y, 054 rotateZ(x, z, widthX(), lengthZ(), inverseRotation), 055 rotate(current, inverseRotation), 056 rotate(approxPlaceable, inverseRotation) 057 ), rotation); 058 } 059 060 @Override 061 public void reset() { 062 schematic.reset(); 063 } 064 065 @Override 066 public int widthX() { 067 return flipsCoordinates(rotation) ? schematic.lengthZ() : schematic.widthX(); 068 } 069 070 @Override 071 public int heightY() { 072 return schematic.heightY(); 073 } 074 075 @Override 076 public int lengthZ() { 077 return flipsCoordinates(rotation) ? schematic.widthX() : schematic.lengthZ(); 078 } 079 080 /** 081 * Wether {@code rotation} swaps the x and z components 082 */ 083 private static boolean flipsCoordinates(Rotation rotation) { 084 return rotation == Rotation.CLOCKWISE_90 || rotation == Rotation.COUNTERCLOCKWISE_90; 085 } 086 087 /** 088 * The x component of x,y after applying the rotation 089 */ 090 private static int rotateX(int x, int z, int sizeX, int sizeZ, Rotation rotation) { 091 switch (rotation) { 092 case NONE: 093 return x; 094 case CLOCKWISE_90: 095 return sizeZ - z - 1; 096 case CLOCKWISE_180: 097 return sizeX - x - 1; 098 case COUNTERCLOCKWISE_90: 099 return z; 100 } 101 throw new IllegalArgumentException("Unknown rotation"); 102 } 103 104 /** 105 * The z component of x,y after applying the rotation 106 */ 107 private static int rotateZ(int x, int z, int sizeX, int sizeZ, Rotation rotation) { 108 switch (rotation) { 109 case NONE: 110 return z; 111 case CLOCKWISE_90: 112 return x; 113 case CLOCKWISE_180: 114 return sizeZ - z - 1; 115 case COUNTERCLOCKWISE_90: 116 return sizeX - x - 1; 117 } 118 throw new IllegalArgumentException("Unknown rotation"); 119 } 120 121 private static BlockState rotate(BlockState state, Rotation rotation) { 122 if (state == null) { 123 return null; 124 } 125 return state.rotate(rotation); 126 } 127 128 private static List<BlockState> rotate(List<BlockState> states, Rotation rotation) { 129 if (states == null) { 130 return null; 131 } 132 return states.stream() 133 .map(s -> rotate(s, rotation)) 134 .collect(Collectors.toList()); 135 } 136}