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