package micdoodle8.mods.galacticraft.core.blocks; import java.util.ArrayList; import java.util.List; import java.util.Random; import micdoodle8.mods.galacticraft.api.block.IPartialSealableBlock; import micdoodle8.mods.galacticraft.api.item.IPaintable; import micdoodle8.mods.galacticraft.core.GCBlocks; import micdoodle8.mods.galacticraft.core.GalacticraftCore; import micdoodle8.mods.galacticraft.core.items.IShiftDescription; import micdoodle8.mods.galacticraft.core.util.EnumSortCategoryBlock; import micdoodle8.mods.galacticraft.core.util.GCCoreUtil; import micdoodle8.mods.galacticraft.core.util.JavaUtil; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.properties.IProperty; import net.minecraft.block.properties.PropertyEnum; import net.minecraft.block.state.BlockState; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.BlockPos; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumWorldBlockLayer; import net.minecraft.util.IStringSerializable; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; public class BlockSpaceGlass extends Block implements IPartialSealableBlock, IShiftDescription, ISortableBlock, IPaintable { public static final PropertyEnum MODEL = PropertyEnum.create("modeltype", GlassModel.class); public static final PropertyEnum ROTATION = PropertyEnum.create("rot", GlassRotation.class); //public static final PropertyInteger PLACING = PropertyInteger.create("placing", 0, 2); //This will define whether originally placed by the player facing NS - EW - or UD public final GlassType type; private final GlassFrame frame; //frameValue corresponds to the damage of the placing item private int color = 0xFFFFFF; private final Block baseBlock; private boolean isClient; private static Class clazz = Blocks.water.getClass().getSuperclass(); public BlockSpaceGlass(String assetName, GlassType newType, GlassFrame newFrame, Block base) { super(Material.glass); this.isClient = GalacticraftCore.proxy.getClass().getName().equals("micdoodle8.mods.galacticraft.core.proxy.ClientProxyCore"); this.type = newType; this.frame = newFrame; this.baseBlock = base == null ? this : base; this.color = frame.getDefaultColor(); this.setUnlocalizedName(assetName); this.setStepSound(Block.soundTypeGlass); this.isBlockContainer = true; this.setDefaultState(this.blockState.getBaseState().withProperty(MODEL, GlassModel.STANDARD_PANE).withProperty(ROTATION, GlassRotation.N)); } @Override protected BlockState createBlockState() { return new BlockState(this, new IProperty[] {MODEL, ROTATION}); } @Override @SideOnly(Side.CLIENT) public void getSubBlocks(Item itemIn, CreativeTabs tab, List<ItemStack> list) { //The plain block variety produces items carrying all variants as damage values //Other block varieties have no corresponding ItemBlock (see registration in GCBlocks) if (this.frame == GlassFrame.PLAIN) { for (int i = 0; i < GlassFrame.values().length; i++) list.add(new ItemStack(itemIn, 1, i)); } } @Override public CreativeTabs getCreativeTabToDisplayOn() { return GalacticraftCore.galacticraftBlocksTab; } @Override public EnumSortCategoryBlock getCategory(int meta) { return EnumSortCategoryBlock.DECORATION; } @Override public IBlockState onBlockPlaced(World worldIn, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int damage, EntityLivingBase placer) { //This allows the different item damage values to place different instances of the block - the instances of the block are constructed in GCBlocks if (damage >= GlassFrame.values().length) damage = 0; switch (GlassFrame.values()[damage]) { case TIN_DECO: { switch (this.type) { case STRONG: return GCBlocks.spaceGlassTinStrong.getDefaultState(); case VANILLA: return GCBlocks.spaceGlassTinVanilla.getDefaultState(); default: return GCBlocks.spaceGlassTinClear.getDefaultState(); } } case PLAIN: default: return this.getDefaultState(); } //TODO: Add PLACING direction } @Override public int damageDropped(IBlockState state) { return this.frame.ordinal(); } @Override public Item getItemDropped(IBlockState state, Random rand, int fortune) { return Item.getItemFromBlock(this.baseBlock); //TODO: override getItemDropped() to return null if we make a broken Space Glass variant... } @Override public List<ItemStack> getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) { ArrayList<ItemStack> ret = new ArrayList<ItemStack>(); ret.add(new ItemStack(this.getItemDropped(state, null, fortune), 1, this.frame.ordinal())); return ret; } @Override public boolean canSilkHarvest(World world, BlockPos pos, IBlockState state, EntityPlayer player) { return true; } @Override public boolean isOpaqueCube() { return false; } @Override public boolean isFullCube() { return false; } @Override public boolean isSealed(World world, BlockPos pos, EnumFacing direction) { return direction.ordinal() > 1; } @Override public Material getMaterial() { if (this.isClient && JavaUtil.instance.isCalledBySpecific(clazz)) { return Material.water; } return this.blockMaterial; } @Override @SideOnly(Side.CLIENT) public boolean shouldSideBeRendered(IBlockAccess worldIn, BlockPos pos, EnumFacing side) { return true; } @Override @SideOnly(Side.CLIENT) public EnumWorldBlockLayer getBlockLayer() { return EnumWorldBlockLayer.TRANSLUCENT; } @Override public boolean canRenderInLayer(EnumWorldBlockLayer layer) { return layer == EnumWorldBlockLayer.TRANSLUCENT || layer == EnumWorldBlockLayer.SOLID; } @Override @SideOnly(Side.CLIENT) public int colorMultiplier(IBlockAccess worldIn, BlockPos pos, int renderPasss) { return this.color; } @Override public void addCollisionBoxesToList(World worldIn, BlockPos pos, IBlockState state, AxisAlignedBB mask, List<AxisAlignedBB> list, Entity collidingEntity) { IBlockState above = worldIn.getBlockState(pos.up()); IBlockState below = worldIn.getBlockState(pos.down()); IBlockState north = worldIn.getBlockState(pos.north()); IBlockState south = worldIn.getBlockState(pos.south()); IBlockState west = worldIn.getBlockState(pos.west()); IBlockState east = worldIn.getBlockState(pos.east()); boolean connectN = this.canPaneConnectToBlock(north, state); boolean connectS = this.canPaneConnectToBlock(south, state); boolean connectW = this.canPaneConnectToBlock(west, state); boolean connectE = this.canPaneConnectToBlock(east, state); boolean plateD = this.buildSolidSide(below, state); boolean plateU = this.buildSolidSide(above, state); boolean plateN = this.buildSolidSide(north, state); boolean plateS = this.buildSolidSide(south, state); boolean plateW = this.buildSolidSide(west, state); boolean plateE = this.buildSolidSide(east, state); //No plate on the sides which glass is facing if (connectN || connectS) { plateW = plateE = false; } if (connectW || connectE) { plateN = plateS = false; } //Singleton if (!connectE && !connectW && !connectN && !connectS) { boolean prefEW = false; if (below.getBlock() == this) { prefEW = (isConnectedEW(below, worldIn, pos.down()) || isPreferenceEW(below, worldIn, pos.down())); } else if (above.getBlock() == this) { prefEW = (isConnectedEW(above, worldIn, pos.up()) || isPreferenceEW(above, worldIn, pos.up())); } if (this.isPreferenceEW(state, worldIn, pos)) prefEW = true; if (prefEW) { plateN = plateS = false; } else { plateW = plateE = false; } } float posGlass = 0.375F; float posBase = 0.225F; float xMin = plateU || plateD || plateN || plateS ? posBase : posGlass; float xMax = plateU || plateD || plateN || plateS ? 1F - posBase : 1F - posGlass; float yMin = 0F; //plateE || plateW || plateN || plateS ? posBase : 0.375F; float yMax = 1F; //plateE || plateW || plateN || plateS ? 0.775F : 0.625F; float zMin = plateU || plateD || plateE || plateW ? posBase : posGlass; float zMax = plateU || plateD || plateE || plateW ? 1F - posBase : 1F - posGlass; if (plateW || connectW) xMin = 0F; if (plateE || connectE) xMax = 1F; if (plateN || connectN) zMin = 0F; if (plateS || connectS) zMax = 1F; //Special for corner diagonals if ((connectW ^ connectE) && (connectN ^ connectS) && !(plateU && plateD)) { float diag = 0.25F; if (connectW) { xMin = diag - 0.01F; xMax = diag; } else { xMin = 1F - diag; xMax = 1.01F - diag; } if (connectN) { zMin = diag - 0.01F; zMax = diag; } else { zMin = 1F - diag; zMax = 1.01F - diag; } } this.setBlockBounds(xMin, yMin, zMin, xMax, yMax, zMax); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } @Override public void setBlockBoundsForItemRender() { this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); } @Override public void setBlockBoundsBasedOnState(IBlockAccess worldIn, BlockPos pos) { IBlockState state = worldIn.getBlockState(pos); IBlockState above = worldIn.getBlockState(pos.up()); IBlockState below = worldIn.getBlockState(pos.down()); IBlockState north = worldIn.getBlockState(pos.north()); IBlockState south = worldIn.getBlockState(pos.south()); IBlockState west = worldIn.getBlockState(pos.west()); IBlockState east = worldIn.getBlockState(pos.east()); boolean connectedN = this.canPaneConnectToBlock(north, state); boolean connectedS = this.canPaneConnectToBlock(south, state); boolean connectedW = this.canPaneConnectToBlock(west, state); boolean connectedE = this.canPaneConnectToBlock(east, state); boolean plateD = this.buildSolidSide(below, state); boolean plateU = this.buildSolidSide(above, state); boolean plateN = this.buildSolidSide(north, state); boolean plateS = this.buildSolidSide(south, state); boolean plateW = this.buildSolidSide(west, state); boolean plateE = this.buildSolidSide(east, state); //No plate on the sides which glass is facing if (connectedN || connectedS) { plateW = plateE = false; } if (connectedW || connectedE) { plateN = plateS = false; } //Singleton if (!connectedE && !connectedW && !connectedN && !connectedS) { boolean prefEW = false; if (below.getBlock() == this) { prefEW = (isConnectedEW(below, worldIn, pos.down()) || isPreferenceEW(below, worldIn, pos.down())); } else if (above.getBlock() == this) { prefEW = (isConnectedEW(above, worldIn, pos.up()) || isPreferenceEW(above, worldIn, pos.up())); } if (this.isPreferenceEW(state, worldIn, pos)) prefEW = true; if (prefEW) { plateN = plateS = false; } else { plateW = plateE = false; } } float f, f1, f2, f3; int solids = (plateD ? 1 : 0) + (plateU ? 1 : 0) + (plateN ? 1 : 0) + (plateS ? 1 : 0) + (plateW ? 1 : 0) + (plateE ? 1 : 0); if (solids > 2 || (plateU && plateD) || (plateW && plateE) || (plateN && plateS)) { //Widen to the frame width, if frames on opposite sides f = 0.25F; f1 = 0.75F; f2 = 0.25F; f3 = 0.75F; } else { //The glass width f = 0.375F; f1 = 0.625F; f2 = 0.375F; f3 = 0.625F; } if (connectedW || plateW) { f = 0.0F; } if (connectedE || plateE) { f1 = 1.0F; } if (connectedN || plateN) { f2 = 0.0F; } if (connectedS || plateS) { f3 = 1.0F; } this.setBlockBounds(f, 0.0F, f2, f1, 1.0F, f3); } @Override public boolean isSideSolid(IBlockAccess world, BlockPos pos, EnumFacing dir) { IBlockState thisBlock = world.getBlockState(pos); if ((dir == EnumFacing.NORTH || dir == EnumFacing.SOUTH) && this.isConnectedEW(thisBlock, world, pos)) return false; if ((dir == EnumFacing.WEST || dir == EnumFacing.EAST) && this.isConnectedNS(thisBlock, world, pos)) return false; IBlockState otherBlock = world.getBlockState(pos.offset(dir.getOpposite())); return this.buildSolidSide(otherBlock, thisBlock); } protected boolean isConnectedEW(IBlockState state, IBlockAccess worldIn, BlockPos pos) { IBlockState west = worldIn.getBlockState(pos.west()); IBlockState east = worldIn.getBlockState(pos.east()); return this.canPaneConnectToBlock(west, state) || this.canPaneConnectToBlock(east, state); } protected boolean isConnectedEWRecursive(IBlockState state, IBlockAccess worldIn, BlockPos pos, EnumFacing dir) { boolean connectN = this.canPaneConnectToBlock(worldIn.getBlockState(pos.north()), state); boolean connectS = this.canPaneConnectToBlock(worldIn.getBlockState(pos.south()), state); boolean connectW = this.canPaneConnectToBlock(worldIn.getBlockState(pos.west()), state); boolean connectE = this.canPaneConnectToBlock(worldIn.getBlockState(pos.east()), state); if (connectN || connectS || connectW || connectE) { return (connectW || connectE) && !connectN && !connectS; } BlockPos next = pos.offset(dir, 1); IBlockState nextState = worldIn.getBlockState(next); if (nextState.getBlock() == this) { return this.isConnectedEWRecursive(nextState, worldIn, next, dir); } return dir == EnumFacing.DOWN && this.isPreferenceEW(state, worldIn, pos); } protected boolean isConnectedNS(IBlockState state, IBlockAccess worldIn, BlockPos pos) { IBlockState north = worldIn.getBlockState(pos.north()); IBlockState south = worldIn.getBlockState(pos.south()); return this.canPaneConnectToBlock(north, state) || this.canPaneConnectToBlock(south, state); } protected boolean isConnectedNSRecursive(IBlockState state, IBlockAccess worldIn, BlockPos pos, EnumFacing dir) { boolean connectN = this.canPaneConnectToBlock(worldIn.getBlockState(pos.north()), state); boolean connectS = this.canPaneConnectToBlock(worldIn.getBlockState(pos.south()), state); boolean connectW = this.canPaneConnectToBlock(worldIn.getBlockState(pos.west()), state); boolean connectE = this.canPaneConnectToBlock(worldIn.getBlockState(pos.east()), state); if (connectN || connectS || connectW || connectE) { return (connectN || connectS) && !connectW && !connectE; } BlockPos next = pos.offset(dir, 1); IBlockState nextState = worldIn.getBlockState(next); if (nextState.getBlock() == this) { return this.isConnectedNSRecursive(nextState, worldIn, next, dir); } return dir == EnumFacing.DOWN && !this.isPreferenceEW(state, worldIn, pos); } protected boolean isPreferenceEW(IBlockState state, IBlockAccess worldIn, BlockPos pos) { IBlockState north = worldIn.getBlockState(pos.north()); IBlockState south = worldIn.getBlockState(pos.south()); IBlockState west = worldIn.getBlockState(pos.west()); IBlockState east = worldIn.getBlockState(pos.east()); int solidsEW = (west.getBlock().isSideSolid(worldIn, pos.west(), EnumFacing.EAST) ? 1 : 0) + (east.getBlock().isSideSolid(worldIn, pos.east(), EnumFacing.WEST) ? 1 : 0); int solidsNS = (north.getBlock().isSideSolid(worldIn, pos.north(), EnumFacing.SOUTH) ? 1 : 0) + (south.getBlock().isSideSolid(worldIn, pos.south(), EnumFacing.NORTH) ? 1 : 0); return solidsEW > solidsNS; } protected boolean canPaneConnectToBlock(IBlockState off, IBlockState blockState) { return off.getBlock() == this; } protected boolean buildSolidSide(IBlockState off, IBlockState blockState) { return !(off.getBlock() == this); } protected boolean buildSolidSideUD(BlockPos pos, EnumFacing testUD, IBlockAccess worldIn, IBlockState blockState) { BlockPos offPos = pos.offset(testUD, 1); IBlockState off = worldIn.getBlockState(offPos); if (off.getBlock() != this) return true; int connThis = (isConnectedEW(blockState, worldIn, pos) ? 2 : 0) + (isConnectedNS(blockState, worldIn, pos) ? 1 : 0); int connOther = (isConnectedEW(off, worldIn, offPos) ? 2 : 0) + (isConnectedNS(off, worldIn, offPos) ? 1 : 0); if (connThis == 0 && connOther == 0) return false; int trueThis = identifyHorizConnections(worldIn, pos, blockState); int trueOther = identifyHorizConnections(worldIn, offPos, off); //Singles (no horizontal connections) -> does it match the plane of the one above or below? if (connThis == 0 && (((trueOther & 3) == 0) && trueThis != 3 || ((trueOther & 12) == 0) && trueThis == 3)) { return false; } if (connOther == 0 && (((trueThis & 3) == 0) && trueOther != 3 || ((trueThis & 12) == 0) && trueOther == 3)) { return false; } //Non-matching planes of connection, including all singles not already dealt with -> solid side if (connThis != connOther) return true; //One side of connection only - and matches plane of the one above/below -> no solid side if (trueThis < 3 || trueThis == 4 || trueThis == 8) { return false; } if (trueOther < 3 || trueOther == 4 || trueOther == 8) { return false; } //Special cases: T junctions above/below 2-way corners, or similar -> solid side because the glass can't connect properly if ((trueThis & 7) != (trueOther & 7)) { return true; } if ((trueThis & 11) != (trueOther & 11)) { return true; } if ((trueThis & 13) != (trueOther & 13)) { return true; } if ((trueThis & 14) != (trueOther & 14)) { return true; } //Anything still left, it's matching planes of connection and not a special case -> no solid side return false; } private int identifyHorizConnections(IBlockAccess worldIn, BlockPos pos, IBlockState state) { IBlockState north = worldIn.getBlockState(pos.north()); IBlockState south = worldIn.getBlockState(pos.south()); IBlockState west = worldIn.getBlockState(pos.west()); IBlockState east = worldIn.getBlockState(pos.east()); boolean connectN = this.canPaneConnectToBlock(north, state); boolean connectS = this.canPaneConnectToBlock(south, state); boolean connectW = this.canPaneConnectToBlock(west, state); boolean connectE = this.canPaneConnectToBlock(east, state); int connections = (connectN ? 1 : 0) + (connectS ? 1 : 0) + (connectW ? 1 : 0) + (connectE ? 1 : 0); if (!connectN && !connectS && !connectW && !connectE) { IBlockState above = worldIn.getBlockState(pos.up()); IBlockState below = worldIn.getBlockState(pos.down()); if (below.getBlock() == this && this.isConnectedEWRecursive(below, worldIn, pos.down(), EnumFacing.DOWN)) { return 3; } else if (above.getBlock() == this && this.isConnectedEWRecursive(above, worldIn, pos.up(), EnumFacing.UP)) { return 3; } if (below.getBlock() == this && this.isConnectedNSRecursive(below, worldIn, pos.down(), EnumFacing.DOWN)) { return 12; } else if (above.getBlock() == this && this.isConnectedNSRecursive(above, worldIn, pos.up(), EnumFacing.UP)) { return 12; } if (this.isPreferenceEW(state, worldIn, pos)) { return 3; } } return (connectN ? 8 : 0) + (connectS ? 4 : 0) + (connectW ? 2 : 0) + (connectE ? 1 : 0); } @Override public IBlockState getActualState(IBlockState state, IBlockAccess worldIn, BlockPos pos) { IBlockState above = worldIn.getBlockState(pos.up()); IBlockState below = worldIn.getBlockState(pos.down()); IBlockState north = worldIn.getBlockState(pos.north()); IBlockState south = worldIn.getBlockState(pos.south()); IBlockState west = worldIn.getBlockState(pos.west()); IBlockState east = worldIn.getBlockState(pos.east()); boolean connectN = this.canPaneConnectToBlock(north, state); boolean connectS = this.canPaneConnectToBlock(south, state); boolean connectW = this.canPaneConnectToBlock(west, state); boolean connectE = this.canPaneConnectToBlock(east, state); boolean plateD = buildSolidSideUD(pos, EnumFacing.DOWN, worldIn, state); boolean plateU = buildSolidSideUD(pos, EnumFacing.UP, worldIn, state); boolean plateN = this.buildSolidSide(north, state); boolean plateS = this.buildSolidSide(south, state); boolean plateW = this.buildSolidSide(west, state); boolean plateE = this.buildSolidSide(east, state); int connections = (connectN ? 1 : 0) + (connectS ? 1 : 0) + (connectW ? 1 : 0) + (connectE ? 1 : 0); GlassRotation rot = GlassRotation.N; int cornerPiece = 0; if (connections == 4) return getModel(state, 4, rot, plateD, false, false, plateU, 0); if (connections == 3) { if (!connectE) rot = GlassRotation.S; else if (!connectN) rot = GlassRotation.E; else if (!connectS) rot = GlassRotation.W; return getModel(state, 3, rot, plateD, false, false, plateU, 0); } if (connections == 0) { if (below.getBlock() == this && this.isConnectedEWRecursive(below, worldIn, pos.down(), EnumFacing.DOWN)) { rot = GlassRotation.E; } else if (above.getBlock() == this && this.isConnectedEWRecursive(above, worldIn, pos.up(), EnumFacing.UP)) { rot = GlassRotation.E; } if (below.getBlock() == this && this.isConnectedNSRecursive(below, worldIn, pos.down(), EnumFacing.DOWN)) { } else if (above.getBlock() == this && this.isConnectedNSRecursive(above, worldIn, pos.up(), EnumFacing.UP)) { } else if (this.isPreferenceEW(state, worldIn, pos)) { rot = GlassRotation.E; } return getModel(state, 1, rot, plateD, plateS, plateN, plateU, 0); } // EnumFacing testUD = EnumFacing.UP; // if (plateU && !plateD) // { // testUD = EnumFacing.DOWN; // } // if (plateD && !plateU) // { // testUD = EnumFacing.UP; // } // Two glass connections in a flat plane - this also covers connected flat on one side only if (connectW && connectE || connections == 1 && (connectW || connectE)) { rot = GlassRotation.E; if (connectW && !plateU && buildSolidSideUD(pos.west(), EnumFacing.UP, worldIn, west)) { cornerPiece++; } if (connectW && !plateD && buildSolidSideUD(pos.west(), EnumFacing.DOWN, worldIn, west)) { cornerPiece += 5; } if (connectE && !plateU && buildSolidSideUD(pos.east(), EnumFacing.UP, worldIn, east)) { cornerPiece++; if (connectW) rot = GlassRotation.W; } if (connectE && !plateD && buildSolidSideUD(pos.east(), EnumFacing.DOWN, worldIn, east)) { cornerPiece += 5; if (connectW) rot = GlassRotation.W; } return getModel(state, 1, rot, plateD, plateW, plateE, plateU, cornerPiece); } if (connectN && connectS || connections == 1) { if (connectN && !plateU && buildSolidSideUD(pos.north(), EnumFacing.UP, worldIn, north)) { if (!connectS) { cornerPiece |= 5; if (!plateD) rot = GlassRotation.S; } else { cornerPiece |= 1; rot = GlassRotation.S; } } if (connectN && !plateD && buildSolidSideUD(pos.north(), EnumFacing.DOWN, worldIn, north)) { cornerPiece ++; if (connectS) rot = GlassRotation.S; } if (connectS && !plateU && buildSolidSideUD(pos.south(), EnumFacing.UP, worldIn, south)) { if (cornerPiece == 0 && !plateD) { cornerPiece = 5; rot = GlassRotation.S; } else if ((cornerPiece & 3) < 2) { cornerPiece ++; } } if (connectS && !plateD && buildSolidSideUD(pos.south(), EnumFacing.DOWN, worldIn, south)) { if ((cornerPiece & 3) < 2) { cornerPiece ++; } else { cornerPiece |= 5; //rot = GlassRotation.S; } } return getModel(state, 1, rot, plateD, plateS, plateN, plateU, cornerPiece); } //It must be two glass connections on a corner if (connectW && connectS) rot = GlassRotation.S; else if (connectS && connectE) rot = GlassRotation.E; else if (connectN && connectW) rot = GlassRotation.W; return getModel(state, 2, rot, plateD, false, false, plateU, 0); } private IBlockState getModel(IBlockState state, int model, GlassRotation rot, boolean plateD, boolean plateL, boolean plateR, boolean plateU, int cornerPiece) { int x = 0; int y = rot.ordinal(); if (y % 2 == 1) y = y ^ 2; int solids = (plateD ? 1 : 0) + (plateU ? 1 : 0) + (plateR ? 1 : 0) + (plateL ? 1 : 0); switch (model) { case 1: if (solids == 4) return state.withProperty(MODEL, GlassModel.STANDARD_S4).withProperty(ROTATION, rot.get(y, 0)); if (solids == 3) { if (!plateD) x = ( y % 2 == 1) ? 3 : 1; else if (!plateR) { x = 2; y = y ^ 2; } else if (!plateU) x = ( y % 2 == 1) ? 1 :3; return state.withProperty(MODEL, GlassModel.STANDARD_S3).withProperty(ROTATION, rot.get(y, x)); } if (plateD && plateU) return state.withProperty(MODEL, GlassModel.STANDARD_S2A).withProperty(ROTATION, rot.get(y, 0)); if (plateL && plateR) return state.withProperty(MODEL, GlassModel.STANDARD_S2A).withProperty(ROTATION, rot.get(y, 1)); if (plateD && (plateR || plateL)) { return state.withProperty(MODEL, cornerPiece > 0 ? GlassModel.STANDARD_S2B : GlassModel.STANDARD_S2).withProperty(ROTATION, rot.get(plateL ? (y ^ 2) : y, 0)); } if (plateU && (plateR || plateL)) { return state.withProperty(MODEL, cornerPiece > 0 ? GlassModel.STANDARD_S2B : GlassModel.STANDARD_S2).withProperty(ROTATION, rot.get(plateL ? (y ^ 2) : y, 2)); } if (plateU || plateD) return state.withProperty(MODEL, getCornerModel(cornerPiece)).withProperty(ROTATION, rot.get(y, (plateU || cornerPiece > 4) ? 2 : 0)); if (plateR || plateL) return state.withProperty(MODEL, getCornerModel(cornerPiece)).withProperty(ROTATION, rot.get(plateL ? (y ^ 2) : y, 1 + ( cornerPiece > 4 ? 2 : 0))); return state.withProperty(MODEL, GlassModel.STANDARD_PANE).withProperty(ROTATION, rot.get(y, 0)); case 2: if (plateU && plateD) return state.withProperty(MODEL, GlassModel.CORNER_S2).withProperty(ROTATION, rot.get(y, 0)); if (plateD) return state.withProperty(MODEL, GlassModel.CORNER_S).withProperty(ROTATION, rot.get(y, 0)); if (plateU) return state.withProperty(MODEL, GlassModel.CORNER_S).withProperty(ROTATION, rot.get((y + 3) % 4, 2)); return state.withProperty(MODEL, GlassModel.CORNER).withProperty(ROTATION, rot.get(y, 0)); case 3: if (plateD && plateU) return state.withProperty(MODEL, GlassModel.T_JUNCTION_S2).withProperty(ROTATION, rot.get(y, 0)); if (plateD) return state.withProperty(MODEL, GlassModel.T_JUNCTION_S).withProperty(ROTATION, rot.get(y, 0)); if (plateU) return state.withProperty(MODEL, GlassModel.T_JUNCTION_S).withProperty(ROTATION, rot.get(y ^ 2, 2)); return state.withProperty(MODEL, GlassModel.T_JUNCTION).withProperty(ROTATION, rot.get(y, x)); case 4: if (plateD && plateU) return state.withProperty(MODEL, GlassModel.CROSSROADS_S2).withProperty(ROTATION, rot.get(y, 0)); if (plateD) return state.withProperty(MODEL, GlassModel.CROSSROADS_S).withProperty(ROTATION, rot.get(y, 0)); if (plateU) return state.withProperty(MODEL, GlassModel.CROSSROADS_S).withProperty(ROTATION, rot.get(y ^ 2, 2)); default: return state.withProperty(MODEL, GlassModel.CROSSROADS).withProperty(ROTATION, rot.get(y, x)); } } private Comparable getCornerModel(int cornerPiece) { if ((cornerPiece & 2) == 2) return GlassModel.STANDARD_S1BB; return cornerPiece > 0 ? GlassModel.STANDARD_S1B : GlassModel.STANDARD_S1; } @Override public IBlockState getStateFromMeta(int meta) { return this.getDefaultState(); } @Override public int getMetaFromState(IBlockState state) { return 0; } @Override public int setColor(int newColor, EntityPlayer p, Side side) { if (newColor >= 0 && this.color != newColor) { this.color = newColor; return 1; } return 0; } @SideOnly(Side.CLIENT) public static void updateGlassColors(int color1, int color2, int color3) { int changes = 0; changes += GCBlocks.spaceGlassVanilla.setColor(color1, null, Side.CLIENT); changes += GCBlocks.spaceGlassClear.setColor(color2, null, Side.CLIENT); changes += GCBlocks.spaceGlassStrong.setColor(color3, null, Side.CLIENT); if (changes > 0) BlockSpaceGlass.updateClientRender(); } @SideOnly(Side.CLIENT) public static void updateClientRender() { Minecraft.getMinecraft().renderGlobal.loadRenderers(); //TODO: improve performance, this is re-rendering ALL chunks on client //Can we somehow limit this to chunks containing BlockSpaceGlass? //or else: don't do all the chunk redrawing at once, queue them? } @Override public String getShiftDescription(int meta) { switch (this.type) { case CLEAR: return GCCoreUtil.translate("tile.space_glass.clear.description"); case VANILLA: return GCCoreUtil.translate("tile.space_glass.description"); case STRONG: default: return GCCoreUtil.translate("tile.space_glass.strong.description"); } } @Override public boolean showDescription(int meta) { return true; } public enum GlassModel implements IStringSerializable { STANDARD_PANE("standard"), CORNER("corner"), T_JUNCTION("joint"), CROSSROADS("joinx"), STANDARD_S1("standards1"), STANDARD_S1B("standards1b"), STANDARD_S1BB("standards1bb"), STANDARD_S2("standards2"), STANDARD_S2A("standards2a"), STANDARD_S2B("standards2b"), STANDARD_S3("standards3"), STANDARD_S4("standards4"), CORNER_S("corner_s"), CORNER_S2("corner_s2"), T_JUNCTION_S("joint_s"), T_JUNCTION_S2("joint_s2"), CROSSROADS_S("joinx_s"), CROSSROADS_S2("joinx_s2"); private final String name; private GlassModel(String name) { this.name = name; } @Override public String getName() { return this.name; } } public enum GlassRotation implements IStringSerializable { N("0"), E("y"), S("yy"), W("yyy"), UN("u"), UE("uyyy"), US("uyy"), UW("uy"), UUN("uuyy"), UUE("uuyyy"), UUS("uu"), UUW("uuy"), DN("d"), DE("dy"), DS("dyy"), DW("dyyy"); private final String name; private GlassRotation(String name) { this.name = name; } @Override public String getName() { return this.name; } private static GlassRotation get(int i) { return GlassRotation.values()[i]; } private static GlassRotation get(int y, int x) { int i = y + x *4; return GlassRotation.values()[i]; } } public enum GlassFrame implements IStringSerializable { PLAIN("plain", 0xfafaf7), TIN_DECO("tin_deco", 0xFFFFFF); //TODO - more frame textures can be added in future - maybe only on Asteroids? private final String name; private final int defaultColor; private GlassFrame (String name, int color) { this.name = name; this.defaultColor = color; } @Override public String getName() { return this.name; } public int getDefaultColor() { return this.defaultColor; } } public enum GlassType implements IStringSerializable { VANILLA("vanilla"), CLEAR("clear"), STRONG("strong"); private final String name; private GlassType (String name) { this.name = name; } @Override public String getName() { return this.name; } } }