001 package net.minecraft.src; 002 003 import java.util.Random; 004 005 import net.minecraftforge.common.ForgeDirection; 006 import static net.minecraftforge.common.ForgeDirection.*; 007 008 public class BlockRail extends Block 009 { 010 /** Power related rails have this field at true. */ 011 private final boolean isPowered; 012 013 /** 014 * Forge: Moved render type to a field and a setter. 015 * This allows for a mod to change the render type 016 * for vanilla rails, and any mod rails that extend 017 * this class. 018 */ 019 private int renderType = 9; 020 021 public void setRenderType(int value) 022 { 023 renderType = value; 024 } 025 026 /** 027 * Returns true if the block at the coordinates of world passed is a valid rail block (current is rail, powered or 028 * detector). 029 */ 030 public static final boolean isRailBlockAt(World par0World, int par1, int par2, int par3) 031 { 032 int var4 = par0World.getBlockId(par1, par2, par3); 033 return isRailBlock(var4); 034 } 035 036 /** 037 * Return true if the parameter is a blockID for a valid rail block (current is rail, powered or detector). 038 */ 039 public static final boolean isRailBlock(int par0) 040 { 041 return Block.blocksList[par0] instanceof BlockRail; 042 } 043 044 protected BlockRail(int par1, int par2, boolean par3) 045 { 046 super(par1, par2, Material.circuits); 047 this.isPowered = par3; 048 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); 049 this.setCreativeTab(CreativeTabs.tabTransport); 050 } 051 052 /** 053 * Returns true if the block is power related rail. 054 */ 055 public boolean isPowered() 056 { 057 return this.isPowered; 058 } 059 060 /** 061 * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been 062 * cleared to be reused) 063 */ 064 public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4) 065 { 066 return null; 067 } 068 069 /** 070 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 071 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 072 */ 073 public boolean isOpaqueCube() 074 { 075 return false; 076 } 077 078 /** 079 * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world, 080 * x, y, z, startVec, endVec 081 */ 082 public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3) 083 { 084 this.setBlockBoundsBasedOnState(par1World, par2, par3, par4); 085 return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3); 086 } 087 088 /** 089 * Updates the blocks bounds based on its current state. Args: world, x, y, z 090 */ 091 public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 092 { 093 int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4); 094 095 if (var5 >= 2 && var5 <= 5) 096 { 097 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F); 098 } 099 else 100 { 101 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); 102 } 103 } 104 105 /** 106 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata 107 */ 108 public int getBlockTextureFromSideAndMetadata(int par1, int par2) 109 { 110 if (this.isPowered) 111 { 112 if (this.blockID == Block.railPowered.blockID && (par2 & 8) == 0) 113 { 114 return this.blockIndexInTexture - 16; 115 } 116 } 117 else if (par2 >= 6) 118 { 119 return this.blockIndexInTexture - 16; 120 } 121 122 return this.blockIndexInTexture; 123 } 124 125 /** 126 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 127 */ 128 public boolean renderAsNormalBlock() 129 { 130 return false; 131 } 132 133 /** 134 * The type of render function that is called for this block 135 */ 136 public int getRenderType() 137 { 138 return renderType; 139 } 140 141 /** 142 * Returns the quantity of items to drop on block destruction. 143 */ 144 public int quantityDropped(Random par1Random) 145 { 146 return 1; 147 } 148 149 /** 150 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z 151 */ 152 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4) 153 { 154 return par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP); 155 } 156 157 /** 158 * Called whenever the block is added into the world. Args: world, x, y, z 159 */ 160 public void onBlockAdded(World par1World, int par2, int par3, int par4) 161 { 162 if (!par1World.isRemote) 163 { 164 this.refreshTrackShape(par1World, par2, par3, par4, true); 165 166 if (this.blockID == Block.railPowered.blockID) 167 { 168 this.onNeighborBlockChange(par1World, par2, par3, par4, this.blockID); 169 } 170 } 171 } 172 173 /** 174 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 175 * their own) Args: x, y, z, neighbor blockID 176 */ 177 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 178 { 179 if (!par1World.isRemote) 180 { 181 int var6 = par1World.getBlockMetadata(par2, par3, par4); 182 int var7 = var6; 183 184 if (this.isPowered) 185 { 186 var7 = var6 & 7; 187 } 188 189 boolean var8 = false; 190 191 if (!par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP)) 192 { 193 var8 = true; 194 } 195 196 if (var7 == 2 && !par1World.isBlockSolidOnSide(par2 + 1, par3, par4, UP)) 197 { 198 var8 = true; 199 } 200 201 if (var7 == 3 && !par1World.isBlockSolidOnSide(par2 - 1, par3, par4, UP)) 202 { 203 var8 = true; 204 } 205 206 if (var7 == 4 && !par1World.isBlockSolidOnSide(par2, par3, par4 - 1, UP)) 207 { 208 var8 = true; 209 } 210 211 if (var7 == 5 && !par1World.isBlockSolidOnSide(par2, par3, par4 + 1, UP)) 212 { 213 var8 = true; 214 } 215 216 if (var8) 217 { 218 this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0); 219 par1World.setBlockWithNotify(par2, par3, par4, 0); 220 } 221 else if (this.blockID == Block.railPowered.blockID) 222 { 223 boolean var9 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4); 224 var9 = var9 || this.isNeighborRailPowered(par1World, par2, par3, par4, var6, true, 0) || this.isNeighborRailPowered(par1World, par2, par3, par4, var6, false, 0); 225 boolean var10 = false; 226 227 if (var9 && (var6 & 8) == 0) 228 { 229 par1World.setBlockMetadataWithNotify(par2, par3, par4, var7 | 8); 230 var10 = true; 231 } 232 else if (!var9 && (var6 & 8) != 0) 233 { 234 par1World.setBlockMetadataWithNotify(par2, par3, par4, var7); 235 var10 = true; 236 } 237 238 if (var10) 239 { 240 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 241 242 if (var7 == 2 || var7 == 3 || var7 == 4 || var7 == 5) 243 { 244 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 245 } 246 } 247 } 248 else if (par5 > 0 && Block.blocksList[par5].canProvidePower() && !this.isPowered && RailLogic.getNAdjacentTracks(new RailLogic(this, par1World, par2, par3, par4)) == 3) 249 { 250 this.refreshTrackShape(par1World, par2, par3, par4, false); 251 } 252 } 253 } 254 255 /** 256 * Completely recalculates the track shape based on neighboring tracks 257 */ 258 private void refreshTrackShape(World par1World, int par2, int par3, int par4, boolean par5) 259 { 260 if (!par1World.isRemote) 261 { 262 (new RailLogic(this, par1World, par2, par3, par4)).refreshTrackShape(par1World.isBlockIndirectlyGettingPowered(par2, par3, par4), par5); 263 } 264 } 265 266 /** 267 * Powered minecart rail is conductive like wire, so check for powered neighbors 268 */ 269 private boolean isNeighborRailPowered(World par1World, int par2, int par3, int par4, int par5, boolean par6, int par7) 270 { 271 if (par7 >= 8) 272 { 273 return false; 274 } 275 else 276 { 277 int var8 = par5 & 7; 278 boolean var9 = true; 279 280 switch (var8) 281 { 282 case 0: 283 if (par6) 284 { 285 ++par4; 286 } 287 else 288 { 289 --par4; 290 } 291 292 break; 293 case 1: 294 if (par6) 295 { 296 --par2; 297 } 298 else 299 { 300 ++par2; 301 } 302 303 break; 304 case 2: 305 if (par6) 306 { 307 --par2; 308 } 309 else 310 { 311 ++par2; 312 ++par3; 313 var9 = false; 314 } 315 316 var8 = 1; 317 break; 318 case 3: 319 if (par6) 320 { 321 --par2; 322 ++par3; 323 var9 = false; 324 } 325 else 326 { 327 ++par2; 328 } 329 330 var8 = 1; 331 break; 332 case 4: 333 if (par6) 334 { 335 ++par4; 336 } 337 else 338 { 339 --par4; 340 ++par3; 341 var9 = false; 342 } 343 344 var8 = 0; 345 break; 346 case 5: 347 if (par6) 348 { 349 ++par4; 350 ++par3; 351 var9 = false; 352 } 353 else 354 { 355 --par4; 356 } 357 358 var8 = 0; 359 } 360 361 return this.isRailPassingPower(par1World, par2, par3, par4, par6, par7, var8) ? true : var9 && this.isRailPassingPower(par1World, par2, par3 - 1, par4, par6, par7, var8); 362 } 363 } 364 365 /** 366 * Returns true if the specified rail is passing power to its neighbor 367 */ 368 private boolean isRailPassingPower(World par1World, int par2, int par3, int par4, boolean par5, int par6, int par7) 369 { 370 int var8 = par1World.getBlockId(par2, par3, par4); 371 372 if (var8 == Block.railPowered.blockID) 373 { 374 int var9 = par1World.getBlockMetadata(par2, par3, par4); 375 int var10 = var9 & 7; 376 377 if (par7 == 1 && (var10 == 0 || var10 == 4 || var10 == 5)) 378 { 379 return false; 380 } 381 382 if (par7 == 0 && (var10 == 1 || var10 == 2 || var10 == 3)) 383 { 384 return false; 385 } 386 387 if ((var9 & 8) != 0) 388 { 389 if (par1World.isBlockIndirectlyGettingPowered(par2, par3, par4)) 390 { 391 return true; 392 } 393 394 return this.isNeighborRailPowered(par1World, par2, par3, par4, var9, par5, par6 + 1); 395 } 396 } 397 398 return false; 399 } 400 401 /** 402 * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility 403 * and stop pistons 404 */ 405 public int getMobilityFlag() 406 { 407 return 0; 408 } 409 410 /** 411 * Return true if the blocks passed is a power related rail. 412 * @deprecated 413 * This function is no longer called by Minecraft 414 */ 415 @Deprecated 416 static boolean isPoweredBlockRail(BlockRail par0BlockRail) 417 { 418 return par0BlockRail.isPowered; 419 } 420 421 /** 422 * Return true if the rail can make corners. 423 * Used by placement logic. 424 * @param world The world. 425 * @param x The rail X coordinate. 426 * @param y The rail Y coordinate. 427 * @param z The rail Z coordinate. 428 * @return True if the rail can make corners. 429 */ 430 public boolean isFlexibleRail(World world, int y, int x, int z) 431 { 432 return !isPowered; 433 } 434 435 /** 436 * Returns true if the rail can make up and down slopes. 437 * Used by placement logic. 438 * @param world The world. 439 * @param x The rail X coordinate. 440 * @param y The rail Y coordinate. 441 * @param z The rail Z coordinate. 442 * @return True if the rail can make slopes. 443 */ 444 public boolean canMakeSlopes(World world, int x, int y, int z) 445 { 446 return true; 447 } 448 449 /** 450 * Return the rails metadata (without the power bit if the rail uses one). 451 * Can be used to make the cart think the rail something other than it is, 452 * for example when making diamond junctions or switches. 453 * The cart parameter will often be null unless it it called from EntityMinecart. 454 * 455 * Valid rail metadata is defined as follows: 456 * 0x0: flat track going North-South 457 * 0x1: flat track going West-East 458 * 0x2: track ascending to the East 459 * 0x3: track ascending to the West 460 * 0x4: track ascending to the North 461 * 0x5: track ascending to the South 462 * 0x6: WestNorth corner (connecting East and South) 463 * 0x7: EastNorth corner (connecting West and South) 464 * 0x8: EastSouth corner (connecting West and North) 465 * 0x9: WestSouth corner (connecting East and North) 466 * 467 * All directions are Notch defined. 468 * In MC Beta 1.8.3 the Sun rises in the North. 469 * In MC 1.0.0 the Sun rises in the East. 470 * 471 * @param world The world. 472 * @param cart The cart asking for the metadata, null if it is not called by EntityMinecart. 473 * @param y The rail X coordinate. 474 * @param x The rail Y coordinate. 475 * @param z The rail Z coordinate. 476 * @return The metadata. 477 */ 478 public int getBasicRailMetadata(IBlockAccess world, EntityMinecart cart, int x, int y, int z) 479 { 480 int meta = world.getBlockMetadata(x, y, z); 481 if(isPowered) 482 { 483 meta = meta & 7; 484 } 485 return meta; 486 } 487 488 /** 489 * Returns the max speed of the rail at the specified position. 490 * @param world The world. 491 * @param cart The cart on the rail, may be null. 492 * @param x The rail X coordinate. 493 * @param y The rail Y coordinate. 494 * @param z The rail Z coordinate. 495 * @return The max speed of the current rail. 496 */ 497 public float getRailMaxSpeed(World world, EntityMinecart cart, int y, int x, int z) 498 { 499 return 0.4f; 500 } 501 502 /** 503 * This function is called by any minecart that passes over this rail. 504 * It is called once per update tick that the minecart is on the rail. 505 * @param world The world. 506 * @param cart The cart on the rail. 507 * @param y The rail X coordinate. 508 * @param x The rail Y coordinate. 509 * @param z The rail Z coordinate. 510 */ 511 public void onMinecartPass(World world, EntityMinecart cart, int y, int x, int z) 512 { 513 } 514 515 /** 516 * Return true if this rail uses the 4th bit as a power bit. 517 * Avoid using this function when getBasicRailMetadata() can be used instead. 518 * The only reason to use this function is if you wish to change the rails metadata. 519 * @param world The world. 520 * @param x The rail X coordinate. 521 * @param y The rail Y coordinate. 522 * @param z The rail Z coordinate. 523 * @return True if the 4th bit is a power bit. 524 */ 525 public boolean hasPowerBit(World world, int x, int y, int z) 526 { 527 return isPowered; 528 } 529 }