001package net.minecraft.block; 002 003import java.util.Random; 004import net.minecraft.block.material.Material; 005import net.minecraft.creativetab.CreativeTabs; 006import net.minecraft.entity.item.EntityMinecart; 007import net.minecraft.util.AxisAlignedBB; 008import net.minecraft.util.MovingObjectPosition; 009import net.minecraft.util.Vec3; 010import net.minecraft.world.IBlockAccess; 011import net.minecraft.world.World; 012 013public abstract class BlockRailBase extends Block 014{ 015 /** Power related rails have this field at true. */ 016 protected final boolean isPowered; 017 018 /** 019 * Returns true if the block at the coordinates of world passed is a valid rail block (current is rail, powered or 020 * detector). 021 */ 022 public static final boolean isRailBlockAt(World par0World, int par1, int par2, int par3) 023 { 024 return isRailBlock(par0World.getBlockId(par1, par2, par3)); 025 } 026 027 /** 028 * Return true if the parameter is a blockID for a valid rail block (current is rail, powered or detector). 029 */ 030 public static final boolean isRailBlock(int par0) 031 { 032 return Block.blocksList[par0] instanceof BlockRailBase; 033 } 034 035 protected BlockRailBase(int par1, boolean par2) 036 { 037 super(par1, Material.circuits); 038 this.isPowered = par2; 039 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); 040 this.setCreativeTab(CreativeTabs.tabTransport); 041 } 042 043 /** 044 * Returns true if the block is power related rail. 045 */ 046 public boolean isPowered() 047 { 048 return this.isPowered; 049 } 050 051 /** 052 * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been 053 * cleared to be reused) 054 */ 055 public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4) 056 { 057 return null; 058 } 059 060 /** 061 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 062 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 063 */ 064 public boolean isOpaqueCube() 065 { 066 return false; 067 } 068 069 /** 070 * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world, 071 * x, y, z, startVec, endVec 072 */ 073 public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3) 074 { 075 this.setBlockBoundsBasedOnState(par1World, par2, par3, par4); 076 return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3); 077 } 078 079 /** 080 * Updates the blocks bounds based on its current state. Args: world, x, y, z 081 */ 082 public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 083 { 084 int l = par1IBlockAccess.getBlockMetadata(par2, par3, par4); 085 086 if (l >= 2 && l <= 5) 087 { 088 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F); 089 } 090 else 091 { 092 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); 093 } 094 } 095 096 /** 097 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 098 */ 099 public boolean renderAsNormalBlock() 100 { 101 return false; 102 } 103 104 /** 105 * The type of render function that is called for this block 106 */ 107 public int getRenderType() 108 { 109 return renderType; 110 } 111 112 /** 113 * Returns the quantity of items to drop on block destruction. 114 */ 115 public int quantityDropped(Random par1Random) 116 { 117 return 1; 118 } 119 120 /** 121 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z 122 */ 123 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4) 124 { 125 return par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4); 126 } 127 128 /** 129 * Called whenever the block is added into the world. Args: world, x, y, z 130 */ 131 public void onBlockAdded(World par1World, int par2, int par3, int par4) 132 { 133 if (!par1World.isRemote) 134 { 135 this.refreshTrackShape(par1World, par2, par3, par4, true); 136 137 if (this.isPowered) 138 { 139 this.onNeighborBlockChange(par1World, par2, par3, par4, this.blockID); 140 } 141 } 142 } 143 144 /** 145 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 146 * their own) Args: x, y, z, neighbor blockID 147 */ 148 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 149 { 150 if (!par1World.isRemote) 151 { 152 int i1 = par1World.getBlockMetadata(par2, par3, par4); 153 int j1 = i1; 154 155 if (this.isPowered) 156 { 157 j1 = i1 & 7; 158 } 159 160 boolean flag = false; 161 162 if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4)) 163 { 164 flag = true; 165 } 166 167 if (j1 == 2 && !par1World.doesBlockHaveSolidTopSurface(par2 + 1, par3, par4)) 168 { 169 flag = true; 170 } 171 172 if (j1 == 3 && !par1World.doesBlockHaveSolidTopSurface(par2 - 1, par3, par4)) 173 { 174 flag = true; 175 } 176 177 if (j1 == 4 && !par1World.doesBlockHaveSolidTopSurface(par2, par3, par4 - 1)) 178 { 179 flag = true; 180 } 181 182 if (j1 == 5 && !par1World.doesBlockHaveSolidTopSurface(par2, par3, par4 + 1)) 183 { 184 flag = true; 185 } 186 187 if (flag) 188 { 189 this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0); 190 par1World.func_94571_i(par2, par3, par4); 191 } 192 else 193 { 194 this.func_94358_a(par1World, par2, par3, par4, i1, j1, par5); 195 } 196 } 197 } 198 199 protected void func_94358_a(World par1World, int par2, int par3, int par4, int par5, int par6, int par7) {} 200 201 /** 202 * Completely recalculates the track shape based on neighboring tracks 203 */ 204 protected void refreshTrackShape(World par1World, int par2, int par3, int par4, boolean par5) 205 { 206 if (!par1World.isRemote) 207 { 208 (new BlockBaseRailLogic(this, par1World, par2, par3, par4)).func_94511_a(par1World.isBlockIndirectlyGettingPowered(par2, par3, par4), par5); 209 } 210 } 211 212 /** 213 * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility 214 * and stop pistons 215 */ 216 public int getMobilityFlag() 217 { 218 return 0; 219 } 220 221 /** 222 * ejects contained items into the world, and notifies neighbours of an update, as appropriate 223 */ 224 public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6) 225 { 226 int j1 = par6; 227 228 if (this.isPowered) 229 { 230 j1 = par6 & 7; 231 } 232 233 super.breakBlock(par1World, par2, par3, par4, par5, par6); 234 235 if (j1 == 2 || j1 == 3 || j1 == 4 || j1 == 5) 236 { 237 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, par5); 238 } 239 240 if (this.isPowered) 241 { 242 par1World.notifyBlocksOfNeighborChange(par2, par3, par4, par5); 243 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, par5); 244 } 245 } 246 247 /** 248 * Return true if the rail can make corners. 249 * Used by placement logic. 250 * @param world The world. 251 * @param x The rail X coordinate. 252 * @param y The rail Y coordinate. 253 * @param z The rail Z coordinate. 254 * @return True if the rail can make corners. 255 */ 256 public boolean isFlexibleRail(World world, int y, int x, int z) 257 { 258 return !isPowered; 259 } 260 261 /** 262 * Returns true if the rail can make up and down slopes. 263 * Used by placement logic. 264 * @param world The world. 265 * @param x The rail X coordinate. 266 * @param y The rail Y coordinate. 267 * @param z The rail Z coordinate. 268 * @return True if the rail can make slopes. 269 */ 270 public boolean canMakeSlopes(World world, int x, int y, int z) 271 { 272 return true; 273 } 274 275 /** 276 * Return the rail's metadata (without the power bit if the rail uses one). 277 * Can be used to make the cart think the rail something other than it is, 278 * for example when making diamond junctions or switches. 279 * The cart parameter will often be null unless it it called from EntityMinecart. 280 * 281 * Valid rail metadata is defined as follows: 282 * 0x0: flat track going North-South 283 * 0x1: flat track going West-East 284 * 0x2: track ascending to the East 285 * 0x3: track ascending to the West 286 * 0x4: track ascending to the North 287 * 0x5: track ascending to the South 288 * 0x6: WestNorth corner (connecting East and South) 289 * 0x7: EastNorth corner (connecting West and South) 290 * 0x8: EastSouth corner (connecting West and North) 291 * 0x9: WestSouth corner (connecting East and North) 292 * 293 * @param world The world. 294 * @param cart The cart asking for the metadata, null if it is not called by EntityMinecart. 295 * @param y The rail X coordinate. 296 * @param x The rail Y coordinate. 297 * @param z The rail Z coordinate. 298 * @return The metadata. 299 */ 300 public int getBasicRailMetadata(IBlockAccess world, EntityMinecart cart, int x, int y, int z) 301 { 302 int meta = world.getBlockMetadata(x, y, z); 303 if(isPowered) 304 { 305 meta = meta & 7; 306 } 307 return meta; 308 } 309 310 /** 311 * Returns the max speed of the rail at the specified position. 312 * @param world The world. 313 * @param cart The cart on the rail, may be null. 314 * @param x The rail X coordinate. 315 * @param y The rail Y coordinate. 316 * @param z The rail Z coordinate. 317 * @return The max speed of the current rail. 318 */ 319 public float getRailMaxSpeed(World world, EntityMinecart cart, int y, int x, int z) 320 { 321 return 0.4f; 322 } 323 324 /** 325 * This function is called by any minecart that passes over this rail. 326 * It is called once per update tick that the minecart is on the rail. 327 * @param world The world. 328 * @param cart The cart on the rail. 329 * @param y The rail X coordinate. 330 * @param x The rail Y coordinate. 331 * @param z The rail Z coordinate. 332 */ 333 public void onMinecartPass(World world, EntityMinecart cart, int y, int x, int z) 334 { 335 } 336 337 /** 338 * Forge: Moved render type to a field and a setter. 339 * This allows for a mod to change the render type 340 * for vanilla rails, and any mod rails that extend 341 * this class. 342 */ 343 private int renderType = 9; 344 345 public void setRenderType(int value) 346 { 347 renderType = value; 348 } 349}