001 package net.minecraft.block; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 import java.util.ArrayList; 006 import java.util.HashSet; 007 import java.util.Random; 008 import java.util.Set; 009 import net.minecraft.block.material.Material; 010 import net.minecraft.item.Item; 011 import net.minecraft.util.AxisAlignedBB; 012 import net.minecraft.util.Direction; 013 import net.minecraft.world.ChunkPosition; 014 import net.minecraft.world.IBlockAccess; 015 import net.minecraft.world.World; 016 017 public class BlockRedstoneWire extends Block 018 { 019 /** 020 * When false, power transmission methods do not look at other redstone wires. Used internally during 021 * updateCurrentStrength. 022 */ 023 private boolean wiresProvidePower = true; 024 private Set blocksNeedingUpdate = new HashSet(); 025 026 public BlockRedstoneWire(int par1, int par2) 027 { 028 super(par1, par2, Material.circuits); 029 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.0625F, 1.0F); 030 } 031 032 /** 033 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata 034 */ 035 public int getBlockTextureFromSideAndMetadata(int par1, int par2) 036 { 037 return this.blockIndexInTexture; 038 } 039 040 /** 041 * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been 042 * cleared to be reused) 043 */ 044 public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4) 045 { 046 return null; 047 } 048 049 /** 050 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 051 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 052 */ 053 public boolean isOpaqueCube() 054 { 055 return false; 056 } 057 058 /** 059 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 060 */ 061 public boolean renderAsNormalBlock() 062 { 063 return false; 064 } 065 066 /** 067 * The type of render function that is called for this block 068 */ 069 public int getRenderType() 070 { 071 return 5; 072 } 073 074 @SideOnly(Side.CLIENT) 075 076 /** 077 * Returns a integer with hex for 0xrrggbb with this color multiplied against the blocks color. Note only called 078 * when first determining what to render. 079 */ 080 public int colorMultiplier(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 081 { 082 return 8388608; 083 } 084 085 /** 086 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z 087 */ 088 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4) 089 { 090 return par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) || par1World.getBlockId(par2, par3 - 1, par4) == Block.glowStone.blockID; 091 } 092 093 /** 094 * Sets the strength of the wire current (0-15) for this block based on neighboring blocks and propagates to 095 * neighboring redstone wires 096 */ 097 private void updateAndPropagateCurrentStrength(World par1World, int par2, int par3, int par4) 098 { 099 this.calculateCurrentChanges(par1World, par2, par3, par4, par2, par3, par4); 100 ArrayList var5 = new ArrayList(this.blocksNeedingUpdate); 101 this.blocksNeedingUpdate.clear(); 102 103 for (int var6 = 0; var6 < var5.size(); ++var6) 104 { 105 ChunkPosition var7 = (ChunkPosition)var5.get(var6); 106 par1World.notifyBlocksOfNeighborChange(var7.x, var7.y, var7.z, this.blockID); 107 } 108 } 109 110 private void calculateCurrentChanges(World par1World, int par2, int par3, int par4, int par5, int par6, int par7) 111 { 112 int var8 = par1World.getBlockMetadata(par2, par3, par4); 113 int var9 = 0; 114 this.wiresProvidePower = false; 115 boolean var10 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4); 116 this.wiresProvidePower = true; 117 int var11; 118 int var12; 119 int var13; 120 121 if (var10) 122 { 123 var9 = 15; 124 } 125 else 126 { 127 for (var11 = 0; var11 < 4; ++var11) 128 { 129 var12 = par2; 130 var13 = par4; 131 132 if (var11 == 0) 133 { 134 var12 = par2 - 1; 135 } 136 137 if (var11 == 1) 138 { 139 ++var12; 140 } 141 142 if (var11 == 2) 143 { 144 var13 = par4 - 1; 145 } 146 147 if (var11 == 3) 148 { 149 ++var13; 150 } 151 152 if (var12 != par5 || par3 != par6 || var13 != par7) 153 { 154 var9 = this.getMaxCurrentStrength(par1World, var12, par3, var13, var9); 155 } 156 157 if (par1World.isBlockNormalCube(var12, par3, var13) && !par1World.isBlockNormalCube(par2, par3 + 1, par4)) 158 { 159 if (var12 != par5 || par3 + 1 != par6 || var13 != par7) 160 { 161 var9 = this.getMaxCurrentStrength(par1World, var12, par3 + 1, var13, var9); 162 } 163 } 164 else if (!par1World.isBlockNormalCube(var12, par3, var13) && (var12 != par5 || par3 - 1 != par6 || var13 != par7)) 165 { 166 var9 = this.getMaxCurrentStrength(par1World, var12, par3 - 1, var13, var9); 167 } 168 } 169 170 if (var9 > 0) 171 { 172 --var9; 173 } 174 else 175 { 176 var9 = 0; 177 } 178 } 179 180 if (var8 != var9) 181 { 182 par1World.editingBlocks = true; 183 par1World.setBlockMetadataWithNotify(par2, par3, par4, var9); 184 par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4); 185 par1World.editingBlocks = false; 186 187 for (var11 = 0; var11 < 4; ++var11) 188 { 189 var12 = par2; 190 var13 = par4; 191 int var14 = par3 - 1; 192 193 if (var11 == 0) 194 { 195 var12 = par2 - 1; 196 } 197 198 if (var11 == 1) 199 { 200 ++var12; 201 } 202 203 if (var11 == 2) 204 { 205 var13 = par4 - 1; 206 } 207 208 if (var11 == 3) 209 { 210 ++var13; 211 } 212 213 if (par1World.isBlockNormalCube(var12, par3, var13)) 214 { 215 var14 += 2; 216 } 217 218 boolean var15 = false; 219 int var16 = this.getMaxCurrentStrength(par1World, var12, par3, var13, -1); 220 var9 = par1World.getBlockMetadata(par2, par3, par4); 221 222 if (var9 > 0) 223 { 224 --var9; 225 } 226 227 if (var16 >= 0 && var16 != var9) 228 { 229 this.calculateCurrentChanges(par1World, var12, par3, var13, par2, par3, par4); 230 } 231 232 var16 = this.getMaxCurrentStrength(par1World, var12, var14, var13, -1); 233 var9 = par1World.getBlockMetadata(par2, par3, par4); 234 235 if (var9 > 0) 236 { 237 --var9; 238 } 239 240 if (var16 >= 0 && var16 != var9) 241 { 242 this.calculateCurrentChanges(par1World, var12, var14, var13, par2, par3, par4); 243 } 244 } 245 246 if (var8 < var9 || var9 == 0) 247 { 248 this.blocksNeedingUpdate.add(new ChunkPosition(par2, par3, par4)); 249 this.blocksNeedingUpdate.add(new ChunkPosition(par2 - 1, par3, par4)); 250 this.blocksNeedingUpdate.add(new ChunkPosition(par2 + 1, par3, par4)); 251 this.blocksNeedingUpdate.add(new ChunkPosition(par2, par3 - 1, par4)); 252 this.blocksNeedingUpdate.add(new ChunkPosition(par2, par3 + 1, par4)); 253 this.blocksNeedingUpdate.add(new ChunkPosition(par2, par3, par4 - 1)); 254 this.blocksNeedingUpdate.add(new ChunkPosition(par2, par3, par4 + 1)); 255 } 256 } 257 } 258 259 /** 260 * Calls World.notifyBlocksOfNeighborChange() for all neighboring blocks, but only if the given block is a redstone 261 * wire. 262 */ 263 private void notifyWireNeighborsOfNeighborChange(World par1World, int par2, int par3, int par4) 264 { 265 if (par1World.getBlockId(par2, par3, par4) == this.blockID) 266 { 267 par1World.notifyBlocksOfNeighborChange(par2, par3, par4, this.blockID); 268 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID); 269 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID); 270 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID); 271 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID); 272 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 273 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 274 } 275 } 276 277 /** 278 * Called whenever the block is added into the world. Args: world, x, y, z 279 */ 280 public void onBlockAdded(World par1World, int par2, int par3, int par4) 281 { 282 super.onBlockAdded(par1World, par2, par3, par4); 283 284 if (!par1World.isRemote) 285 { 286 this.updateAndPropagateCurrentStrength(par1World, par2, par3, par4); 287 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 288 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 289 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3, par4); 290 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3, par4); 291 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3, par4 - 1); 292 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3, par4 + 1); 293 294 if (par1World.isBlockNormalCube(par2 - 1, par3, par4)) 295 { 296 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3 + 1, par4); 297 } 298 else 299 { 300 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3 - 1, par4); 301 } 302 303 if (par1World.isBlockNormalCube(par2 + 1, par3, par4)) 304 { 305 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3 + 1, par4); 306 } 307 else 308 { 309 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3 - 1, par4); 310 } 311 312 if (par1World.isBlockNormalCube(par2, par3, par4 - 1)) 313 { 314 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 + 1, par4 - 1); 315 } 316 else 317 { 318 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 - 1, par4 - 1); 319 } 320 321 if (par1World.isBlockNormalCube(par2, par3, par4 + 1)) 322 { 323 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 + 1, par4 + 1); 324 } 325 else 326 { 327 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 - 1, par4 + 1); 328 } 329 } 330 } 331 332 /** 333 * ejects contained items into the world, and notifies neighbours of an update, as appropriate 334 */ 335 public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6) 336 { 337 super.breakBlock(par1World, par2, par3, par4, par5, par6); 338 339 if (!par1World.isRemote) 340 { 341 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 342 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 343 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID); 344 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID); 345 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID); 346 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID); 347 this.updateAndPropagateCurrentStrength(par1World, par2, par3, par4); 348 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3, par4); 349 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3, par4); 350 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3, par4 - 1); 351 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3, par4 + 1); 352 353 if (par1World.isBlockNormalCube(par2 - 1, par3, par4)) 354 { 355 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3 + 1, par4); 356 } 357 else 358 { 359 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3 - 1, par4); 360 } 361 362 if (par1World.isBlockNormalCube(par2 + 1, par3, par4)) 363 { 364 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3 + 1, par4); 365 } 366 else 367 { 368 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3 - 1, par4); 369 } 370 371 if (par1World.isBlockNormalCube(par2, par3, par4 - 1)) 372 { 373 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 + 1, par4 - 1); 374 } 375 else 376 { 377 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 - 1, par4 - 1); 378 } 379 380 if (par1World.isBlockNormalCube(par2, par3, par4 + 1)) 381 { 382 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 + 1, par4 + 1); 383 } 384 else 385 { 386 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 - 1, par4 + 1); 387 } 388 } 389 } 390 391 /** 392 * Returns the current strength at the specified block if it is greater than the passed value, or the passed value 393 * otherwise. Signature: (world, x, y, z, strength) 394 */ 395 private int getMaxCurrentStrength(World par1World, int par2, int par3, int par4, int par5) 396 { 397 if (par1World.getBlockId(par2, par3, par4) != this.blockID) 398 { 399 return par5; 400 } 401 else 402 { 403 int var6 = par1World.getBlockMetadata(par2, par3, par4); 404 return var6 > par5 ? var6 : par5; 405 } 406 } 407 408 /** 409 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 410 * their own) Args: x, y, z, neighbor blockID 411 */ 412 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 413 { 414 if (!par1World.isRemote) 415 { 416 int var6 = par1World.getBlockMetadata(par2, par3, par4); 417 boolean var7 = this.canPlaceBlockAt(par1World, par2, par3, par4); 418 419 if (var7) 420 { 421 this.updateAndPropagateCurrentStrength(par1World, par2, par3, par4); 422 } 423 else 424 { 425 this.dropBlockAsItem(par1World, par2, par3, par4, var6, 0); 426 par1World.setBlockWithNotify(par2, par3, par4, 0); 427 } 428 429 super.onNeighborBlockChange(par1World, par2, par3, par4, par5); 430 } 431 } 432 433 /** 434 * Returns the ID of the items to drop on destruction. 435 */ 436 public int idDropped(int par1, Random par2Random, int par3) 437 { 438 return Item.redstone.itemID; 439 } 440 441 /** 442 * Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z, 443 * side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block. 444 */ 445 public boolean isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 446 { 447 return !this.wiresProvidePower ? false : this.isProvidingWeakPower(par1IBlockAccess, par2, par3, par4, par5); 448 } 449 450 /** 451 * Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube 452 * returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X, 453 * Y, Z, side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block. 454 */ 455 public boolean isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 456 { 457 if (!this.wiresProvidePower) 458 { 459 return false; 460 } 461 else if (par1IBlockAccess.getBlockMetadata(par2, par3, par4) == 0) 462 { 463 return false; 464 } 465 else if (par5 == 1) 466 { 467 return true; 468 } 469 else 470 { 471 boolean var6 = isPoweredOrRepeater(par1IBlockAccess, par2 - 1, par3, par4, 1) || !par1IBlockAccess.isBlockNormalCube(par2 - 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 - 1, par3 - 1, par4, -1); 472 boolean var7 = isPoweredOrRepeater(par1IBlockAccess, par2 + 1, par3, par4, 3) || !par1IBlockAccess.isBlockNormalCube(par2 + 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 + 1, par3 - 1, par4, -1); 473 boolean var8 = isPoweredOrRepeater(par1IBlockAccess, par2, par3, par4 - 1, 2) || !par1IBlockAccess.isBlockNormalCube(par2, par3, par4 - 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 - 1, par4 - 1, -1); 474 boolean var9 = isPoweredOrRepeater(par1IBlockAccess, par2, par3, par4 + 1, 0) || !par1IBlockAccess.isBlockNormalCube(par2, par3, par4 + 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 - 1, par4 + 1, -1); 475 476 if (!par1IBlockAccess.isBlockNormalCube(par2, par3 + 1, par4)) 477 { 478 if (par1IBlockAccess.isBlockNormalCube(par2 - 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 - 1, par3 + 1, par4, -1)) 479 { 480 var6 = true; 481 } 482 483 if (par1IBlockAccess.isBlockNormalCube(par2 + 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 + 1, par3 + 1, par4, -1)) 484 { 485 var7 = true; 486 } 487 488 if (par1IBlockAccess.isBlockNormalCube(par2, par3, par4 - 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 + 1, par4 - 1, -1)) 489 { 490 var8 = true; 491 } 492 493 if (par1IBlockAccess.isBlockNormalCube(par2, par3, par4 + 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 + 1, par4 + 1, -1)) 494 { 495 var9 = true; 496 } 497 } 498 499 return !var8 && !var7 && !var6 && !var9 && par5 >= 2 && par5 <= 5 ? true : (par5 == 2 && var8 && !var6 && !var7 ? true : (par5 == 3 && var9 && !var6 && !var7 ? true : (par5 == 4 && var6 && !var8 && !var9 ? true : par5 == 5 && var7 && !var8 && !var9))); 500 } 501 } 502 503 /** 504 * Can this block provide power. Only wire currently seems to have this change based on its state. 505 */ 506 public boolean canProvidePower() 507 { 508 return this.wiresProvidePower; 509 } 510 511 @SideOnly(Side.CLIENT) 512 513 /** 514 * A randomly called display update to be able to add particles or other items for display 515 */ 516 public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random) 517 { 518 int var6 = par1World.getBlockMetadata(par2, par3, par4); 519 520 if (var6 > 0) 521 { 522 double var7 = (double)par2 + 0.5D + ((double)par5Random.nextFloat() - 0.5D) * 0.2D; 523 double var9 = (double)((float)par3 + 0.0625F); 524 double var11 = (double)par4 + 0.5D + ((double)par5Random.nextFloat() - 0.5D) * 0.2D; 525 float var13 = (float)var6 / 15.0F; 526 float var14 = var13 * 0.6F + 0.4F; 527 528 if (var6 == 0) 529 { 530 var14 = 0.0F; 531 } 532 533 float var15 = var13 * var13 * 0.7F - 0.5F; 534 float var16 = var13 * var13 * 0.6F - 0.7F; 535 536 if (var15 < 0.0F) 537 { 538 var15 = 0.0F; 539 } 540 541 if (var16 < 0.0F) 542 { 543 var16 = 0.0F; 544 } 545 546 par1World.spawnParticle("reddust", var7, var9, var11, (double)var14, (double)var15, (double)var16); 547 } 548 } 549 550 /** 551 * Returns true if redstone wire can connect to the specified block. Params: World, X, Y, Z, side (not a normal 552 * notch-side, this can be 0, 1, 2, 3 or -1) 553 */ 554 public static boolean isPowerProviderOrWire(IBlockAccess par0IBlockAccess, int par1, int par2, int par3, int par4) 555 { 556 int var5 = par0IBlockAccess.getBlockId(par1, par2, par3); 557 558 if (var5 == Block.redstoneWire.blockID) 559 { 560 return true; 561 } 562 else if (var5 == 0) 563 { 564 return false; 565 } 566 else if (var5 != Block.redstoneRepeaterIdle.blockID && var5 != Block.redstoneRepeaterActive.blockID) 567 { 568 return (Block.blocksList[var5] != null && Block.blocksList[var5].canConnectRedstone(par0IBlockAccess, par1, par2, par3, par4)); 569 } 570 else 571 { 572 int var6 = par0IBlockAccess.getBlockMetadata(par1, par2, par3); 573 return par4 == (var6 & 3) || par4 == Direction.footInvisibleFaceRemap[var6 & 3]; 574 } 575 } 576 577 /** 578 * Returns true if the block coordinate passed can provide power, or is a redstone wire, or if its a repeater that 579 * is powered. 580 */ 581 public static boolean isPoweredOrRepeater(IBlockAccess par0IBlockAccess, int par1, int par2, int par3, int par4) 582 { 583 if (isPowerProviderOrWire(par0IBlockAccess, par1, par2, par3, par4)) 584 { 585 return true; 586 } 587 else 588 { 589 int var5 = par0IBlockAccess.getBlockId(par1, par2, par3); 590 591 if (var5 == Block.redstoneRepeaterActive.blockID) 592 { 593 int var6 = par0IBlockAccess.getBlockMetadata(par1, par2, par3); 594 return par4 == (var6 & 3); 595 } 596 else 597 { 598 return false; 599 } 600 } 601 } 602 603 @SideOnly(Side.CLIENT) 604 605 /** 606 * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative) 607 */ 608 public int idPicked(World par1World, int par2, int par3, int par4) 609 { 610 return Item.redstone.itemID; 611 } 612 }