package com.prupe.mcpatcher.ctm;
import com.prupe.mcpatcher.MCLogger;
import com.prupe.mcpatcher.MCPatcherUtils;
import com.prupe.mcpatcher.TexturePackAPI;
import com.prupe.mcpatcher.TileLoader;
import com.prupe.mcpatcher.ctm.TileOverrideImpl$CTM;
import com.prupe.mcpatcher.ctm.TileOverrideImpl$Fixed;
import com.prupe.mcpatcher.ctm.TileOverrideImpl$Horizontal;
import com.prupe.mcpatcher.ctm.TileOverrideImpl$HorizontalVertical;
import com.prupe.mcpatcher.ctm.TileOverrideImpl$Random1;
import com.prupe.mcpatcher.ctm.TileOverrideImpl$Repeat;
import com.prupe.mcpatcher.ctm.TileOverrideImpl$Top;
import com.prupe.mcpatcher.ctm.TileOverrideImpl$Vertical;
import com.prupe.mcpatcher.ctm.TileOverrideImpl$VerticalHorizontal;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.src.Block;
import net.minecraft.src.IBlockAccess;
import net.minecraft.src.Icon;
import net.minecraft.src.ResourceLocation;
abstract class TileOverride implements ITileOverride {
private static final MCLogger logger = MCLogger.getLogger("Connected Textures", "CTM");
static final int BOTTOM_FACE = 0;
static final int TOP_FACE = 1;
static final int NORTH_FACE = 2;
static final int SOUTH_FACE = 3;
static final int WEST_FACE = 4;
static final int EAST_FACE = 5;
static final int REL_L = 0;
static final int REL_DL = 1;
static final int REL_D = 2;
static final int REL_DR = 3;
static final int REL_R = 4;
static final int REL_UR = 5;
static final int REL_U = 6;
static final int REL_UL = 7;
private static final int META_MASK = 65535;
private static final int ORIENTATION_U_D = 0;
private static final int ORIENTATION_E_W = 65536;
private static final int ORIENTATION_N_S = 131072;
private static final int ORIENTATION_E_W_2 = 196608;
private static final int ORIENTATION_N_S_2 = 262144;
private static final int[][] ROTATE_UV_MAP = new int[][] {{4, 5, 2, 3, 1, 0, 2, -2, 2, -2, 0, 0}, {2, 3, 1, 0, 4, 5, 0, 0, 0, 0, -2, 2}, {4, 5, 2, 3, 1, 0, 2, -2, -2, -2, 0, 0}, {2, 3, 1, 0, 4, 5, 0, 0, 0, 0, -2, -2}};
private static final int[] GO_DOWN = new int[] {0, -1, 0};
private static final int[] GO_UP = new int[] {0, 1, 0};
private static final int[] GO_NORTH = new int[] {0, 0, -1};
private static final int[] GO_SOUTH = new int[] {0, 0, 1};
private static final int[] GO_WEST = new int[] { -1, 0, 0};
private static final int[] GO_EAST = new int[] {1, 0, 0};
private static final int[][] NORMALS = new int[][] {GO_DOWN, GO_UP, GO_NORTH, GO_SOUTH, GO_WEST, GO_EAST};
protected static final int[][][] NEIGHBOR_OFFSET = new int[][][] {{GO_WEST, add(GO_WEST, GO_SOUTH), GO_SOUTH, add(GO_EAST, GO_SOUTH), GO_EAST, add(GO_EAST, GO_NORTH), GO_NORTH, add(GO_WEST, GO_NORTH)}, {GO_WEST, add(GO_WEST, GO_SOUTH), GO_SOUTH, add(GO_EAST, GO_SOUTH), GO_EAST, add(GO_EAST, GO_NORTH), GO_NORTH, add(GO_WEST, GO_NORTH)}, {GO_EAST, add(GO_EAST, GO_DOWN), GO_DOWN, add(GO_WEST, GO_DOWN), GO_WEST, add(GO_WEST, GO_UP), GO_UP, add(GO_EAST, GO_UP)}, {GO_WEST, add(GO_WEST, GO_DOWN), GO_DOWN, add(GO_EAST, GO_DOWN), GO_EAST, add(GO_EAST, GO_UP), GO_UP, add(GO_WEST, GO_UP)}, {GO_NORTH, add(GO_NORTH, GO_DOWN), GO_DOWN, add(GO_SOUTH, GO_DOWN), GO_SOUTH, add(GO_SOUTH, GO_UP), GO_UP, add(GO_NORTH, GO_UP)}, {GO_SOUTH, add(GO_SOUTH, GO_DOWN), GO_DOWN, add(GO_NORTH, GO_DOWN), GO_NORTH, add(GO_NORTH, GO_UP), GO_UP, add(GO_SOUTH, GO_UP)}};
private static final int CONNECT_BY_BLOCK = 0;
private static final int CONNECT_BY_TILE = 1;
private static final int CONNECT_BY_MATERIAL = 2;
private static Method parseBiomeList;
private static Method getBiomeIDAt;
private final ResourceLocation propertiesFile;
private final String texturesDirectory;
private final String baseFilename;
private final TileLoader tileLoader;
private final int renderPass;
private final int weight;
private final Set<Integer> matchBlocks;
private final Set<String> matchTiles;
private final int faces;
private final int metadata;
private final int connectType;
private final boolean innerSeams;
private final BitSet biomes;
private final int minHeight;
private final int maxHeight;
private final List<ResourceLocation> tileNames = new ArrayList();
protected Icon[] icons;
private boolean disabled;
private int[] reorient;
private int rotateUV;
protected boolean rotateTop;
static TileOverride create(ResourceLocation propertiesFile, TileLoader tileLoader) {
if (propertiesFile == null) {
return null;
} else {
Properties properties = TexturePackAPI.getProperties(propertiesFile);
if (properties == null) {
return null;
} else {
String method = properties.getProperty("method", "default").trim().toLowerCase();
Object override = null;
if (!method.equals("default") && !method.equals("glass") && !method.equals("ctm")) {
if (method.equals("random")) {
override = new TileOverrideImpl$Random1(propertiesFile, properties, tileLoader);
if (((TileOverride)override).getNumberOfTiles() == 1) {
override = new TileOverrideImpl$Fixed(propertiesFile, properties, tileLoader);
}
} else if (!method.equals("fixed") && !method.equals("static")) {
if (!method.equals("bookshelf") && !method.equals("horizontal")) {
if (!method.equals("horizontal+vertical") && !method.equals("h+v")) {
if (method.equals("vertical")) {
override = new TileOverrideImpl$Vertical(propertiesFile, properties, tileLoader);
} else if (!method.equals("vertical+horizontal") && !method.equals("v+h")) {
if (!method.equals("sandstone") && !method.equals("top")) {
if (!method.equals("repeat") && !method.equals("pattern")) {
logger.error("%s: unknown method \"%s\"", new Object[] {propertiesFile, method});
} else {
override = new TileOverrideImpl$Repeat(propertiesFile, properties, tileLoader);
}
} else {
override = new TileOverrideImpl$Top(propertiesFile, properties, tileLoader);
}
} else {
override = new TileOverrideImpl$VerticalHorizontal(propertiesFile, properties, tileLoader);
}
} else {
override = new TileOverrideImpl$HorizontalVertical(propertiesFile, properties, tileLoader);
}
} else {
override = new TileOverrideImpl$Horizontal(propertiesFile, properties, tileLoader);
}
} else {
override = new TileOverrideImpl$Fixed(propertiesFile, properties, tileLoader);
}
} else {
override = new TileOverrideImpl$CTM(propertiesFile, properties, tileLoader);
}
if (override != null && !((TileOverride)override).disabled) {
String status = ((TileOverride)override).checkTileMap();
if (status != null) {
((TileOverride)override).error("invalid %s tile map: %s", new Object[] {((TileOverride)override).getMethod(), status});
}
}
return (TileOverride)(override != null && !((TileOverride)override).disabled ? override : null);
}
}
}
protected TileOverride(ResourceLocation propertiesFile, Properties properties, TileLoader tileLoader) {
this.propertiesFile = propertiesFile;
this.texturesDirectory = propertiesFile.getResourcePath().replaceFirst("/[^/]*$", "");
this.baseFilename = propertiesFile.getResourcePath().replaceFirst(".*/", "").replaceFirst("\\.properties$", "");
this.tileLoader = tileLoader;
this.loadIcons(properties);
if (this.tileNames.isEmpty()) {
this.error("no images found in %s/", new Object[] {this.texturesDirectory});
}
String[] mappings = new String[Block.blocksList.length];
int flags;
for (flags = 0; flags < Block.blocksList.length; ++flags) {
Block meta = Block.blocksList[flags];
if (meta != null) {
mappings[flags] = meta.getUnlocalizedName();
}
}
this.matchBlocks = this.getIDList(properties, "matchBlocks", "block", mappings);
this.matchTiles = this.getIDList(properties, "matchTiles");
if (this.matchBlocks.isEmpty() && this.matchTiles.isEmpty()) {
this.matchTiles.add(this.baseFilename);
}
flags = 0;
String[] var13 = properties.getProperty("faces", "all").trim().toLowerCase().split("\\s+");
int connectType1 = var13.length;
int biomeList;
for (biomeList = 0; biomeList < connectType1; ++biomeList) {
String e = var13[biomeList];
if (e.equals("bottom")) {
flags |= 1;
} else if (e.equals("top")) {
flags |= 2;
} else if (e.equals("north")) {
flags |= 4;
} else if (e.equals("south")) {
flags |= 8;
} else if (e.equals("east")) {
flags |= 32;
} else if (e.equals("west")) {
flags |= 16;
} else if (!e.equals("side") && !e.equals("sides")) {
if (e.equals("all")) {
flags = -1;
}
} else {
flags |= 60;
}
}
this.faces = flags;
int var12 = 0;
int[] var14 = MCPatcherUtils.parseIntegerList(properties.getProperty("metadata", "0-31"), 0, 31);
biomeList = var14.length;
for (int var16 = 0; var16 < biomeList; ++var16) {
int i = var14[var16];
var12 |= 1 << i;
}
this.metadata = var12;
String var15 = properties.getProperty("connect", "").trim().toLowerCase();
if (var15.equals("")) {
this.connectType = this.matchTiles.isEmpty() ? 0 : 1;
} else if (var15.equals("block")) {
this.connectType = 0;
} else if (var15.equals("tile")) {
this.connectType = 1;
} else if (var15.equals("material")) {
this.connectType = 2;
} else {
this.error("invalid connect type %s", new Object[] {var15});
this.connectType = 0;
}
this.innerSeams = MCPatcherUtils.getBooleanProperty(properties, "innerSeams", false);
String var17 = properties.getProperty("biomes", "");
if (var17.isEmpty()) {
this.biomes = null;
} else {
this.biomes = new BitSet();
if (parseBiomeList != null) {
try {
parseBiomeList.invoke((Object)null, new Object[] {var17, this.biomes});
} catch (Throwable var11) {
var11.printStackTrace();
parseBiomeList = null;
}
}
}
this.minHeight = MCPatcherUtils.getIntProperty(properties, "minHeight", -1);
this.maxHeight = MCPatcherUtils.getIntProperty(properties, "maxHeight", Integer.MAX_VALUE);
this.renderPass = MCPatcherUtils.getIntProperty(properties, "renderPass", -1);
if (this.renderPass > 3) {
this.error("renderPass must be 0-3", new Object[0]);
} else if (this.renderPass >= 0 && !this.matchTiles.isEmpty()) {
this.error("renderPass=%d must be block-based not tile-based", new Object[] {Integer.valueOf(this.renderPass)});
}
this.weight = MCPatcherUtils.getIntProperty(properties, "weight", 0);
}
private boolean addIcon(ResourceLocation resource) {
this.tileNames.add(resource);
return this.tileLoader.preloadTile(resource, this.renderPass > 2);
}
private void loadIcons(Properties properties) {
this.tileNames.clear();
String tileList = properties.getProperty("tiles", "").trim();
if (tileList.equals("")) {
int range = 0;
while (true) {
ResourceLocation arr$ = TileLoader.parseTileAddress(this.propertiesFile, String.valueOf(range));
if (!TexturePackAPI.hasResource(arr$) || !this.addIcon(arr$)) {
break;
}
++range;
}
} else {
Pattern var14 = Pattern.compile("(\\d+)-(\\d+)");
String[] var15 = tileList.split("\\s+");
int len$ = var15.length;
for (int i$ = 0; i$ < len$; ++i$) {
String token = var15[i$];
Matcher matcher = var14.matcher(token);
if (!token.equals("")) {
if (matcher.matches()) {
try {
int resource = Integer.parseInt(matcher.group(1));
int to = Integer.parseInt(matcher.group(2));
for (int i = resource; i <= to; ++i) {
ResourceLocation resource1 = TileLoader.parseTileAddress(this.propertiesFile, String.valueOf(i));
if (TexturePackAPI.hasResource(resource1)) {
this.addIcon(resource1);
} else {
this.warn("could not find image %s", new Object[] {resource1});
// ToDO:
//this.tileNames.add((Object)null);
}
}
} catch (NumberFormatException var13) {
var13.printStackTrace();
}
} else {
ResourceLocation var16 = TileLoader.parseTileAddress(this.propertiesFile, token);
if (var16 == null) {
// ToDo:
this.tileNames.add((ResourceLocation)null);
} else if (TexturePackAPI.hasResource(var16)) {
this.addIcon(var16);
} else {
this.warn("could not find image %s", new Object[] {var16});
// ToDO:
//this.tileNames.add((Object)null);
}
}
}
}
}
}
private Set<Integer> getIDList(Properties properties, String key, String type, String[] mappings) {
HashSet list = new HashSet();
String property = properties.getProperty(key, "");
String[] m = property.split("\\s+");
int e = m.length;
label53:
for (int i$ = 0; i$ < e; ++i$) {
String token = m[i$];
if (!token.equals("")) {
int i;
if (token.matches("\\d+")) {
try {
i = Integer.parseInt(token);
if (i >= 0 && i < mappings.length) {
list.add(Integer.valueOf(i));
} else {
this.warn("%s value %d is out of range", new Object[] {key, Integer.valueOf(i)});
}
} catch (NumberFormatException var13) {
var13.printStackTrace();
}
} else {
for (i = 0; i < mappings.length; ++i) {
if (token.equals(mappings[i])) {
list.add(Integer.valueOf(i));
continue label53;
}
}
this.warn("unknown %s value %s", new Object[] {key, token});
}
}
}
if (list.isEmpty()) {
Matcher var14 = Pattern.compile(type + "(\\d+)").matcher(this.baseFilename);
if (var14.find()) {
try {
list.add(Integer.valueOf(Integer.parseInt(var14.group(1))));
} catch (NumberFormatException var12) {
var12.printStackTrace();
}
}
}
return list;
}
private Set<String> getIDList(Properties properties, String key) {
HashSet list = new HashSet();
String property = properties.getProperty(key, "");
String[] arr$ = property.split("\\s+");
int len$ = arr$.length;
for (int i$ = 0; i$ < len$; ++i$) {
String token = arr$[i$];
if (!token.equals("")) {
if (token.contains("/")) {
if (!token.endsWith(".png")) {
token = token + ".png";
}
ResourceLocation resource = TexturePackAPI.parseResourceLocation(this.propertiesFile, token);
if (resource != null) {
list.add(resource.toString());
}
} else {
list.add(token);
}
}
}
return list;
}
private static int[] add(int[] a, int[] b) {
if (a.length != b.length) {
throw new RuntimeException("arrays to add are not same length");
} else {
int[] c = new int[a.length];
for (int i = 0; i < c.length; ++i) {
c[i] = a[i] + b[i];
}
return c;
}
}
protected int getNumberOfTiles() {
return this.tileNames.size();
}
String checkTileMap() {
return null;
}
boolean requiresFace() {
return false;
}
public String toString() {
return String.format("%s[%s]", new Object[] {this.getMethod(), this.propertiesFile});
}
public final void registerIcons() {
this.icons = new Icon[this.tileNames.size()];
for (int i = 0; i < this.icons.length; ++i) {
this.icons[i] = this.tileLoader.getIcon((ResourceLocation)this.tileNames.get(i));
}
}
final void error(String format, Object ... params) {
if (this.propertiesFile != null) {
logger.error(this.propertiesFile + ": " + format, params);
}
this.disabled = true;
}
final void warn(String format, Object ... params) {
if (this.propertiesFile != null) {
logger.warning(this.propertiesFile + ": " + format, params);
}
}
public final boolean isDisabled() {
return this.disabled;
}
public final Set<Integer> getMatchingBlocks() {
return this.matchBlocks;
}
public final Set<String> getMatchingTiles() {
return this.matchTiles;
}
public final int getRenderPass() {
return this.renderPass;
}
public final int getWeight() {
return this.weight;
}
public int compareTo(ITileOverride o) {
int result = o.getWeight() - this.getWeight();
return result != 0 ? result : (o instanceof TileOverride ? this.baseFilename.compareTo(((TileOverride)o).baseFilename) : -1);
}
final boolean shouldConnect(IBlockAccess blockAccess, Block block, Icon icon, int i, int j, int k, int face, int[] offset) {
int blockID = block.blockID;
int metadata = blockAccess.getBlockMetadata(i, j, k);
i += offset[0];
j += offset[1];
k += offset[2];
int neighborID = blockAccess.getBlockId(i, j, k);
int neighborMeta = blockAccess.getBlockMetadata(i, j, k);
Block neighbor = Block.blocksList[neighborID];
if (this.exclude(neighbor, face, neighborMeta)) {
return false;
} else {
int orientation = getOrientationFromMetadata(block, metadata);
int neighborOrientation = getOrientationFromMetadata(neighbor, neighborMeta);
if ((orientation & -65536) != (neighborOrientation & -65536)) {
return false;
} else if (this.metadata != -1 && (orientation & 65535) != (neighborOrientation & 65535)) {
return false;
} else {
if (face >= 0 && this.innerSeams) {
int[] normal = NORMALS[face];
if (!neighbor.shouldSideBeRendered(blockAccess, i + normal[0], j + normal[1], k + normal[2], face)) {
return false;
}
}
switch (this.connectType) {
case 0:
return neighborID == blockID;
case 1:
return neighbor.getBlockTexture(blockAccess, i, j, k, face) == icon;
case 2:
return block.blockMaterial == neighbor.blockMaterial;
default:
return false;
}
}
}
}
final int reorient(int face) {
return face >= 0 && face <= 5 && this.reorient != null ? this.reorient[face] : face;
}
final int rotateUV(int neighbor) {
return neighbor + this.rotateUV & 7;
}
final boolean exclude(Block block, int face, int metadata) {
if (block == null) {
return true;
} else if ((this.faces & 1 << this.reorient(face)) == 0) {
return true;
} else {
if (this.metadata != -1 && metadata >= 0 && metadata < 32) {
int altMetadata = getOrientationFromMetadata(block, metadata) & 65535;
if ((this.metadata & (1 << metadata | 1 << altMetadata)) == 0) {
return true;
}
}
return false;
}
}
private static int getOrientationFromMetadata(Block block, int metadata) {
int newMeta = metadata;
int orientation = 0;
switch (block.getRenderType()) {
case 31:
switch (metadata & 12) {
case 0:
newMeta = metadata & -13;
return orientation | newMeta;
case 4:
newMeta = metadata & -13;
orientation = 65536;
return orientation | newMeta;
case 8:
newMeta = metadata & -13;
orientation = 131072;
return orientation | newMeta;
default:
return orientation | newMeta;
}
case 39:
switch (metadata) {
case 3:
newMeta = 2;
orientation = 196608;
break;
case 4:
newMeta = 2;
orientation = 262144;
}
}
return orientation | newMeta;
}
private void setupOrientation(int orientation, int face) {
switch (orientation & -65536) {
case 65536:
this.reorient = ROTATE_UV_MAP[0];
this.rotateUV = ROTATE_UV_MAP[0][face + 6];
this.rotateTop = true;
break;
case 131072:
this.reorient = ROTATE_UV_MAP[1];
this.rotateUV = ROTATE_UV_MAP[1][face + 6];
this.rotateTop = false;
break;
case 196608:
this.reorient = ROTATE_UV_MAP[2];
this.rotateUV = ROTATE_UV_MAP[2][face + 6];
this.rotateTop = true;
break;
case 262144:
this.reorient = ROTATE_UV_MAP[3];
this.rotateUV = ROTATE_UV_MAP[3][face + 6];
this.rotateTop = false;
break;
default:
this.reorient = null;
this.rotateUV = 0;
this.rotateTop = false;
}
}
private static int remapFaceByRenderType(Block block, int metadata, int face) {
switch (block.getRenderType()) {
case 8:
switch (metadata) {
case 2:
case 3:
case 4:
case 5:
return metadata;
default:
return face;
}
case 20:
switch (metadata) {
case 1:
return 2;
case 2:
return 5;
case 3:
case 5:
case 6:
case 7:
default:
break;
case 4:
return 3;
case 8:
return 4;
}
}
return face;
}
public final Icon getTile(IBlockAccess blockAccess, Block block, Icon origIcon, int i, int j, int k, int face) {
if (this.icons == null) {
this.error("no images loaded, disabling", new Object[0]);
return null;
} else if (face < 0 && this.requiresFace()) {
this.error("method=%s is not supported for non-standard blocks", new Object[] {this.getMethod()});
return null;
} else if (block != null && !RenderPassAPI.instance.skipThisRenderPass(block, this.renderPass)) {
int metadata = blockAccess.getBlockMetadata(i, j, k);
this.setupOrientation(getOrientationFromMetadata(block, metadata), face);
face = remapFaceByRenderType(block, metadata, face);
if (this.exclude(block, face, metadata)) {
return null;
} else if (j >= this.minHeight && j <= this.maxHeight) {
if (this.biomes != null) {
if (getBiomeIDAt == null) {
return null;
}
try {
int e = ((Integer)getBiomeIDAt.invoke((Object)null, new Object[] {Integer.valueOf(i), Integer.valueOf(j), Integer.valueOf(k)})).intValue();
if (!this.biomes.get(e)) {
return null;
}
} catch (Throwable var10) {
var10.printStackTrace();
getBiomeIDAt = null;
}
}
return this.getTileImpl(blockAccess, block, origIcon, i, j, k, face);
} else {
return null;
}
} else {
return null;
}
}
public final Icon getTile(Block block, Icon origIcon, int face, int metadata) {
if (this.icons == null) {
this.error("no images loaded, disabling", new Object[0]);
return null;
} else if (face < 0 && this.requiresFace()) {
this.error("method=%s is not supported for non-standard blocks", new Object[] {this.getMethod()});
return null;
} else if (this.minHeight < 0 && this.maxHeight >= Integer.MAX_VALUE && this.biomes == null) {
this.setupOrientation(getOrientationFromMetadata(block, metadata), face);
return this.exclude(block, face, metadata) ? null : this.getTileImpl(block, origIcon, face, metadata);
} else {
return null;
}
}
abstract String getMethod();
abstract Icon getTileImpl(IBlockAccess var1, Block var2, Icon var3, int var4, int var5, int var6, int var7);
abstract Icon getTileImpl(Block var1, Icon var2, int var3, int var4);
static {
try {
Class e = Class.forName("com.prupe.mcpatcher.cc.BiomeHelper");
parseBiomeList = e.getDeclaredMethod("parseBiomeList", new Class[] {String.class, BitSet.class});
getBiomeIDAt = e.getDeclaredMethod("getBiomeIDAt", new Class[] {Integer.TYPE, Integer.TYPE, Integer.TYPE});
parseBiomeList.setAccessible(true);
getBiomeIDAt.setAccessible(true);
logger.fine("biome integration active", new Object[0]);
} catch (Throwable var1) {
parseBiomeList = null;
getBiomeIDAt = null;
logger.warning("biome integration failed", new Object[0]);
}
}
}