001 package net.minecraft.world; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 006 import java.io.File; 007 import java.util.ArrayList; 008 import java.util.HashSet; 009 import java.util.Iterator; 010 import java.util.List; 011 import java.util.Random; 012 import java.util.Set; 013 import java.util.TreeSet; 014 import net.minecraft.block.Block; 015 import net.minecraft.block.BlockEventData; 016 import net.minecraft.crash.CrashReport; 017 import net.minecraft.crash.CrashReportCategory; 018 import net.minecraft.entity.Entity; 019 import net.minecraft.entity.EntityTracker; 020 import net.minecraft.entity.EnumCreatureType; 021 import net.minecraft.entity.INpc; 022 import net.minecraft.entity.effect.EntityLightningBolt; 023 import net.minecraft.entity.passive.EntityAnimal; 024 import net.minecraft.entity.passive.EntityWaterMob; 025 import net.minecraft.entity.player.EntityPlayer; 026 import net.minecraft.entity.player.EntityPlayerMP; 027 import net.minecraft.item.Item; 028 import net.minecraft.network.packet.Packet38EntityStatus; 029 import net.minecraft.network.packet.Packet54PlayNoteBlock; 030 import net.minecraft.network.packet.Packet60Explosion; 031 import net.minecraft.network.packet.Packet70GameEvent; 032 import net.minecraft.network.packet.Packet71Weather; 033 import net.minecraft.profiler.Profiler; 034 import net.minecraft.server.MinecraftServer; 035 import net.minecraft.server.management.PlayerManager; 036 import net.minecraft.tileentity.TileEntity; 037 import net.minecraft.util.ChunkCoordinates; 038 import net.minecraft.util.IProgressUpdate; 039 import net.minecraft.util.IntHashMap; 040 import net.minecraft.util.MathHelper; 041 import net.minecraft.util.ReportedException; 042 import net.minecraft.util.Vec3; 043 import net.minecraft.util.WeightedRandom; 044 import net.minecraft.util.WeightedRandomChestContent; 045 import net.minecraft.world.biome.BiomeGenBase; 046 import net.minecraft.world.biome.SpawnListEntry; 047 import net.minecraft.world.biome.WorldChunkManager; 048 import net.minecraft.world.chunk.Chunk; 049 import net.minecraft.world.chunk.IChunkProvider; 050 import net.minecraft.world.chunk.storage.AnvilChunkLoader; 051 import net.minecraft.world.chunk.storage.ExtendedBlockStorage; 052 import net.minecraft.world.chunk.storage.IChunkLoader; 053 import net.minecraft.world.gen.ChunkProviderServer; 054 import net.minecraft.world.gen.feature.WorldGeneratorBonusChest; 055 import net.minecraft.world.storage.ISaveHandler; 056 057 import net.minecraftforge.common.ChestGenHooks; 058 import static net.minecraftforge.common.ChestGenHooks.*; 059 import net.minecraftforge.common.DimensionManager; 060 import net.minecraftforge.common.MinecraftForge; 061 import net.minecraftforge.event.world.WorldEvent; 062 063 public class WorldServer extends World 064 { 065 private final MinecraftServer mcServer; 066 private final EntityTracker theEntityTracker; 067 private final PlayerManager thePlayerManager; 068 private Set field_73064_N; 069 070 /** All work to do in future ticks. */ 071 private TreeSet pendingTickListEntries; 072 public ChunkProviderServer theChunkProviderServer; 073 074 /** set by CommandServerSave{all,Off,On} */ 075 public boolean canNotSave; 076 077 /** is false if there are no players */ 078 private boolean allPlayersSleeping; 079 private int updateEntityTick = 0; 080 private final Teleporter field_85177_Q; 081 082 /** 083 * Double buffer of ServerBlockEventList[] for holding pending BlockEventData's 084 */ 085 private ServerBlockEventList[] blockEventCache = new ServerBlockEventList[] {new ServerBlockEventList((ServerBlockEvent)null), new ServerBlockEventList((ServerBlockEvent)null)}; 086 087 /** 088 * The index into the blockEventCache; either 0, or 1, toggled in sendBlockEventPackets where all BlockEvent are 089 * applied locally and send to clients. 090 */ 091 private int blockEventCacheIndex = 0; 092 public static final WeightedRandomChestContent[] bonusChestContent = new WeightedRandomChestContent[] {new WeightedRandomChestContent(Item.stick.shiftedIndex, 0, 1, 3, 10), new WeightedRandomChestContent(Block.planks.blockID, 0, 1, 3, 10), new WeightedRandomChestContent(Block.wood.blockID, 0, 1, 3, 10), new WeightedRandomChestContent(Item.axeStone.shiftedIndex, 0, 1, 1, 3), new WeightedRandomChestContent(Item.axeWood.shiftedIndex, 0, 1, 1, 5), new WeightedRandomChestContent(Item.pickaxeStone.shiftedIndex, 0, 1, 1, 3), new WeightedRandomChestContent(Item.pickaxeWood.shiftedIndex, 0, 1, 1, 5), new WeightedRandomChestContent(Item.appleRed.shiftedIndex, 0, 2, 3, 5), new WeightedRandomChestContent(Item.bread.shiftedIndex, 0, 2, 3, 3)}; 093 094 /** An IntHashMap of entity IDs (integers) to their Entity objects. */ 095 private IntHashMap entityIdMap; 096 097 /** Stores the recently processed (lighting) chunks */ 098 protected Set<ChunkCoordIntPair> doneChunks = new HashSet<ChunkCoordIntPair>(); 099 public List<Teleporter> customTeleporters = new ArrayList<Teleporter>(); 100 101 public WorldServer(MinecraftServer par1MinecraftServer, ISaveHandler par2ISaveHandler, String par3Str, int par4, WorldSettings par5WorldSettings, Profiler par6Profiler) 102 { 103 super(par2ISaveHandler, par3Str, par5WorldSettings, WorldProvider.getProviderForDimension(par4), par6Profiler); 104 this.mcServer = par1MinecraftServer; 105 this.theEntityTracker = new EntityTracker(this); 106 this.thePlayerManager = new PlayerManager(this, par1MinecraftServer.getConfigurationManager().getViewDistance()); 107 108 if (this.entityIdMap == null) 109 { 110 this.entityIdMap = new IntHashMap(); 111 } 112 113 if (this.field_73064_N == null) 114 { 115 this.field_73064_N = new HashSet(); 116 } 117 118 if (this.pendingTickListEntries == null) 119 { 120 this.pendingTickListEntries = new TreeSet(); 121 } 122 123 this.field_85177_Q = new Teleporter(this); 124 DimensionManager.setWorld(par4, this); 125 } 126 127 /** 128 * Runs a single tick for the world 129 */ 130 public void tick() 131 { 132 super.tick(); 133 134 if (this.getWorldInfo().isHardcoreModeEnabled() && this.difficultySetting < 3) 135 { 136 this.difficultySetting = 3; 137 } 138 139 this.provider.worldChunkMgr.cleanupCache(); 140 141 if (this.areAllPlayersAsleep()) 142 { 143 boolean var1 = false; 144 145 if (this.spawnHostileMobs && this.difficultySetting >= 1) 146 { 147 ; 148 } 149 150 if (!var1) 151 { 152 long var2 = this.worldInfo.getWorldTime() + 24000L; 153 this.worldInfo.setWorldTime(var2 - var2 % 24000L); 154 this.wakeAllPlayers(); 155 } 156 } 157 158 this.theProfiler.startSection("mobSpawner"); 159 160 if (this.getGameRules().getGameRuleBooleanValue("doMobSpawning")) 161 { 162 SpawnerAnimals.findChunksForSpawning(this, this.spawnHostileMobs, this.spawnPeacefulMobs, this.worldInfo.getWorldTotalTime() % 400L == 0L); 163 } 164 165 this.theProfiler.endStartSection("chunkSource"); 166 this.chunkProvider.unload100OldestChunks(); 167 int var4 = this.calculateSkylightSubtracted(1.0F); 168 169 if (var4 != this.skylightSubtracted) 170 { 171 this.skylightSubtracted = var4; 172 } 173 174 this.sendAndApplyBlockEvents(); 175 this.worldInfo.incrementTotalWorldTime(this.worldInfo.getWorldTotalTime() + 1L); 176 this.worldInfo.setWorldTime(this.worldInfo.getWorldTime() + 1L); 177 this.theProfiler.endStartSection("tickPending"); 178 this.tickUpdates(false); 179 this.theProfiler.endStartSection("tickTiles"); 180 this.tickBlocksAndAmbiance(); 181 this.theProfiler.endStartSection("chunkMap"); 182 this.thePlayerManager.updatePlayerInstances(); 183 this.theProfiler.endStartSection("village"); 184 this.villageCollectionObj.tick(); 185 this.villageSiegeObj.tick(); 186 this.theProfiler.endStartSection("portalForcer"); 187 this.field_85177_Q.func_85189_a(this.getTotalWorldTime()); 188 for (Teleporter tele : customTeleporters) 189 { 190 tele.func_85189_a(getTotalWorldTime()); 191 } 192 this.theProfiler.endSection(); 193 this.sendAndApplyBlockEvents(); 194 } 195 196 /** 197 * only spawns creatures allowed by the chunkProvider 198 */ 199 public SpawnListEntry spawnRandomCreature(EnumCreatureType par1EnumCreatureType, int par2, int par3, int par4) 200 { 201 List var5 = this.getChunkProvider().getPossibleCreatures(par1EnumCreatureType, par2, par3, par4); 202 return var5 != null && !var5.isEmpty() ? (SpawnListEntry)WeightedRandom.getRandomItem(this.rand, var5) : null; 203 } 204 205 /** 206 * Updates the flag that indicates whether or not all players in the world are sleeping. 207 */ 208 public void updateAllPlayersSleepingFlag() 209 { 210 this.allPlayersSleeping = !this.playerEntities.isEmpty(); 211 Iterator var1 = this.playerEntities.iterator(); 212 213 while (var1.hasNext()) 214 { 215 EntityPlayer var2 = (EntityPlayer)var1.next(); 216 217 if (!var2.isPlayerSleeping()) 218 { 219 this.allPlayersSleeping = false; 220 break; 221 } 222 } 223 } 224 225 protected void wakeAllPlayers() 226 { 227 this.allPlayersSleeping = false; 228 Iterator var1 = this.playerEntities.iterator(); 229 230 while (var1.hasNext()) 231 { 232 EntityPlayer var2 = (EntityPlayer)var1.next(); 233 234 if (var2.isPlayerSleeping()) 235 { 236 var2.wakeUpPlayer(false, false, true); 237 } 238 } 239 240 this.resetRainAndThunder(); 241 } 242 243 private void resetRainAndThunder() 244 { 245 provider.resetRainAndThunder(); 246 } 247 248 public boolean areAllPlayersAsleep() 249 { 250 if (this.allPlayersSleeping && !this.isRemote) 251 { 252 Iterator var1 = this.playerEntities.iterator(); 253 EntityPlayer var2; 254 255 do 256 { 257 if (!var1.hasNext()) 258 { 259 return true; 260 } 261 262 var2 = (EntityPlayer)var1.next(); 263 } 264 while (var2.isPlayerFullyAsleep()); 265 266 return false; 267 } 268 else 269 { 270 return false; 271 } 272 } 273 274 @SideOnly(Side.CLIENT) 275 276 /** 277 * Sets a new spawn location by finding an uncovered block at a random (x,z) location in the chunk. 278 */ 279 public void setSpawnLocation() 280 { 281 if (this.worldInfo.getSpawnY() <= 0) 282 { 283 this.worldInfo.setSpawnY(64); 284 } 285 286 int var1 = this.worldInfo.getSpawnX(); 287 int var2 = this.worldInfo.getSpawnZ(); 288 int var3 = 0; 289 290 while (this.getFirstUncoveredBlock(var1, var2) == 0) 291 { 292 var1 += this.rand.nextInt(8) - this.rand.nextInt(8); 293 var2 += this.rand.nextInt(8) - this.rand.nextInt(8); 294 ++var3; 295 296 if (var3 == 10000) 297 { 298 break; 299 } 300 } 301 302 this.worldInfo.setSpawnX(var1); 303 this.worldInfo.setSpawnZ(var2); 304 } 305 306 /** 307 * plays random cave ambient sounds and runs updateTick on random blocks within each chunk in the vacinity of a 308 * player 309 */ 310 protected void tickBlocksAndAmbiance() 311 { 312 super.tickBlocksAndAmbiance(); 313 int var1 = 0; 314 int var2 = 0; 315 Iterator var3 = this.activeChunkSet.iterator(); 316 317 doneChunks.retainAll(activeChunkSet); 318 if (doneChunks.size() == activeChunkSet.size()) 319 { 320 doneChunks.clear(); 321 } 322 323 final long startTime = System.nanoTime(); 324 325 while (var3.hasNext()) 326 { 327 ChunkCoordIntPair var4 = (ChunkCoordIntPair)var3.next(); 328 int var5 = var4.chunkXPos * 16; 329 int var6 = var4.chunkZPos * 16; 330 this.theProfiler.startSection("getChunk"); 331 Chunk var7 = this.getChunkFromChunkCoords(var4.chunkXPos, var4.chunkZPos); 332 this.moodSoundAndLightCheck(var5, var6, var7); 333 this.theProfiler.endStartSection("tickChunk"); 334 //Limits and evenly distributes the lighting update time 335 if (System.nanoTime() - startTime <= 4000000 && doneChunks.add(var4)) 336 { 337 var7.updateSkylight(); 338 } 339 this.theProfiler.endStartSection("thunder"); 340 int var8; 341 int var9; 342 int var10; 343 int var11; 344 345 if (provider.canDoLightning(var7) && this.rand.nextInt(100000) == 0 && this.isRaining() && this.isThundering()) 346 { 347 this.updateLCG = this.updateLCG * 3 + 1013904223; 348 var8 = this.updateLCG >> 2; 349 var9 = var5 + (var8 & 15); 350 var10 = var6 + (var8 >> 8 & 15); 351 var11 = this.getPrecipitationHeight(var9, var10); 352 353 if (this.canLightningStrikeAt(var9, var11, var10)) 354 { 355 this.addWeatherEffect(new EntityLightningBolt(this, (double)var9, (double)var11, (double)var10)); 356 } 357 } 358 359 this.theProfiler.endStartSection("iceandsnow"); 360 int var13; 361 362 if (provider.canDoRainSnowIce(var7) && this.rand.nextInt(16) == 0) 363 { 364 this.updateLCG = this.updateLCG * 3 + 1013904223; 365 var8 = this.updateLCG >> 2; 366 var9 = var8 & 15; 367 var10 = var8 >> 8 & 15; 368 var11 = this.getPrecipitationHeight(var9 + var5, var10 + var6); 369 370 if (this.isBlockFreezableNaturally(var9 + var5, var11 - 1, var10 + var6)) 371 { 372 this.setBlockWithNotify(var9 + var5, var11 - 1, var10 + var6, Block.ice.blockID); 373 } 374 375 if (this.isRaining() && this.canSnowAt(var9 + var5, var11, var10 + var6)) 376 { 377 this.setBlockWithNotify(var9 + var5, var11, var10 + var6, Block.snow.blockID); 378 } 379 380 if (this.isRaining()) 381 { 382 BiomeGenBase var12 = this.getBiomeGenForCoords(var9 + var5, var10 + var6); 383 384 if (var12.canSpawnLightningBolt()) 385 { 386 var13 = this.getBlockId(var9 + var5, var11 - 1, var10 + var6); 387 388 if (var13 != 0) 389 { 390 Block.blocksList[var13].fillWithRain(this, var9 + var5, var11 - 1, var10 + var6); 391 } 392 } 393 } 394 } 395 396 this.theProfiler.endStartSection("tickTiles"); 397 ExtendedBlockStorage[] var19 = var7.getBlockStorageArray(); 398 var9 = var19.length; 399 400 for (var10 = 0; var10 < var9; ++var10) 401 { 402 ExtendedBlockStorage var21 = var19[var10]; 403 404 if (var21 != null && var21.getNeedsRandomTick()) 405 { 406 for (int var20 = 0; var20 < 3; ++var20) 407 { 408 this.updateLCG = this.updateLCG * 3 + 1013904223; 409 var13 = this.updateLCG >> 2; 410 int var14 = var13 & 15; 411 int var15 = var13 >> 8 & 15; 412 int var16 = var13 >> 16 & 15; 413 int var17 = var21.getExtBlockID(var14, var16, var15); 414 ++var2; 415 Block var18 = Block.blocksList[var17]; 416 417 if (var18 != null && var18.getTickRandomly()) 418 { 419 ++var1; 420 var18.updateTick(this, var14 + var5, var16 + var21.getYLocation(), var15 + var6, this.rand); 421 } 422 } 423 } 424 } 425 426 this.theProfiler.endSection(); 427 } 428 } 429 430 /** 431 * Schedules a tick to a block with a delay (Most commonly the tick rate) 432 */ 433 public void scheduleBlockUpdate(int par1, int par2, int par3, int par4, int par5) 434 { 435 this.func_82740_a(par1, par2, par3, par4, par5, 0); 436 } 437 438 public void func_82740_a(int par1, int par2, int par3, int par4, int par5, int par6) 439 { 440 NextTickListEntry var7 = new NextTickListEntry(par1, par2, par3, par4); 441 boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(var7.xCoord >> 4, var7.zCoord >> 4)); 442 byte var8 = isForced ? (byte)0 : 8; 443 444 if (this.scheduledUpdatesAreImmediate && par4 > 0) 445 { 446 if (Block.blocksList[par4].func_82506_l()) 447 { 448 if (this.checkChunksExist(var7.xCoord - var8, var7.yCoord - var8, var7.zCoord - var8, var7.xCoord + var8, var7.yCoord + var8, var7.zCoord + var8)) 449 { 450 int var9 = this.getBlockId(var7.xCoord, var7.yCoord, var7.zCoord); 451 452 if (var9 == var7.blockID && var9 > 0) 453 { 454 Block.blocksList[var9].updateTick(this, var7.xCoord, var7.yCoord, var7.zCoord, this.rand); 455 } 456 } 457 458 return; 459 } 460 461 par5 = 1; 462 } 463 464 if (this.checkChunksExist(par1 - var8, par2 - var8, par3 - var8, par1 + var8, par2 + var8, par3 + var8)) 465 { 466 if (par4 > 0) 467 { 468 var7.setScheduledTime((long)par5 + this.worldInfo.getWorldTotalTime()); 469 var7.func_82753_a(par6); 470 } 471 472 if (!this.field_73064_N.contains(var7)) 473 { 474 this.field_73064_N.add(var7); 475 this.pendingTickListEntries.add(var7); 476 } 477 } 478 } 479 480 /** 481 * Schedules a block update from the saved information in a chunk. Called when the chunk is loaded. 482 */ 483 public void scheduleBlockUpdateFromLoad(int par1, int par2, int par3, int par4, int par5) 484 { 485 NextTickListEntry var6 = new NextTickListEntry(par1, par2, par3, par4); 486 487 if (par4 > 0) 488 { 489 var6.setScheduledTime((long)par5 + this.worldInfo.getWorldTotalTime()); 490 } 491 492 if (!this.field_73064_N.contains(var6)) 493 { 494 this.field_73064_N.add(var6); 495 this.pendingTickListEntries.add(var6); 496 } 497 } 498 499 /** 500 * Updates (and cleans up) entities and tile entities 501 */ 502 public void updateEntities() 503 { 504 if (this.playerEntities.isEmpty() && getPersistentChunks().isEmpty()) 505 { 506 if (this.updateEntityTick++ >= 1200) 507 { 508 return; 509 } 510 } 511 else 512 { 513 this.resetUpdateEntityTick(); 514 } 515 516 super.updateEntities(); 517 } 518 519 /** 520 * Resets the updateEntityTick field to 0 521 */ 522 public void resetUpdateEntityTick() 523 { 524 this.updateEntityTick = 0; 525 } 526 527 /** 528 * Runs through the list of updates to run and ticks them 529 */ 530 public boolean tickUpdates(boolean par1) 531 { 532 int var2 = this.pendingTickListEntries.size(); 533 534 if (var2 != this.field_73064_N.size()) 535 { 536 throw new IllegalStateException("TickNextTick list out of synch"); 537 } 538 else 539 { 540 if (var2 > 1000) 541 { 542 var2 = 1000; 543 } 544 545 for (int var3 = 0; var3 < var2; ++var3) 546 { 547 NextTickListEntry var4 = (NextTickListEntry)this.pendingTickListEntries.first(); 548 549 if (!par1 && var4.scheduledTime > this.worldInfo.getWorldTotalTime()) 550 { 551 break; 552 } 553 554 this.pendingTickListEntries.remove(var4); 555 this.field_73064_N.remove(var4); 556 boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(var4.xCoord >> 4, var4.zCoord >> 4)); 557 byte var5 = isForced ? (byte)0 : 8; 558 559 if (this.checkChunksExist(var4.xCoord - var5, var4.yCoord - var5, var4.zCoord - var5, var4.xCoord + var5, var4.yCoord + var5, var4.zCoord + var5)) 560 { 561 int var6 = this.getBlockId(var4.xCoord, var4.yCoord, var4.zCoord); 562 563 if (var6 == var4.blockID && var6 > 0) 564 { 565 try 566 { 567 Block.blocksList[var6].updateTick(this, var4.xCoord, var4.yCoord, var4.zCoord, this.rand); 568 } 569 catch (Throwable var13) 570 { 571 CrashReport var8 = CrashReport.makeCrashReport(var13, "Exception while ticking a block"); 572 CrashReportCategory var9 = var8.makeCategory("Block being ticked"); 573 int var10; 574 575 try 576 { 577 var10 = this.getBlockMetadata(var4.xCoord, var4.yCoord, var4.zCoord); 578 } 579 catch (Throwable var12) 580 { 581 var10 = -1; 582 } 583 584 CrashReportCategory.func_85068_a(var9, var4.xCoord, var4.yCoord, var4.zCoord, var6, var10); 585 throw new ReportedException(var8); 586 } 587 } 588 } 589 } 590 591 return !this.pendingTickListEntries.isEmpty(); 592 } 593 } 594 595 public List getPendingBlockUpdates(Chunk par1Chunk, boolean par2) 596 { 597 ArrayList var3 = null; 598 ChunkCoordIntPair var4 = par1Chunk.getChunkCoordIntPair(); 599 int var5 = var4.chunkXPos << 4; 600 int var6 = var5 + 16; 601 int var7 = var4.chunkZPos << 4; 602 int var8 = var7 + 16; 603 Iterator var9 = this.pendingTickListEntries.iterator(); 604 605 while (var9.hasNext()) 606 { 607 NextTickListEntry var10 = (NextTickListEntry)var9.next(); 608 609 if (var10.xCoord >= var5 && var10.xCoord < var6 && var10.zCoord >= var7 && var10.zCoord < var8) 610 { 611 if (par2) 612 { 613 this.field_73064_N.remove(var10); 614 var9.remove(); 615 } 616 617 if (var3 == null) 618 { 619 var3 = new ArrayList(); 620 } 621 622 var3.add(var10); 623 } 624 } 625 626 return var3; 627 } 628 629 /** 630 * Will update the entity in the world if the chunk the entity is in is currently loaded or its forced to update. 631 * Args: entity, forceUpdate 632 */ 633 public void updateEntityWithOptionalForce(Entity par1Entity, boolean par2) 634 { 635 if (!this.mcServer.getCanSpawnAnimals() && (par1Entity instanceof EntityAnimal || par1Entity instanceof EntityWaterMob)) 636 { 637 par1Entity.setDead(); 638 } 639 640 if (!this.mcServer.getCanSpawnNPCs() && par1Entity instanceof INpc) 641 { 642 par1Entity.setDead(); 643 } 644 645 if (!(par1Entity.riddenByEntity instanceof EntityPlayer)) 646 { 647 super.updateEntityWithOptionalForce(par1Entity, par2); 648 } 649 } 650 651 /** 652 * direct call to super.updateEntityWithOptionalForce 653 */ 654 public void uncheckedUpdateEntity(Entity par1Entity, boolean par2) 655 { 656 super.updateEntityWithOptionalForce(par1Entity, par2); 657 } 658 659 /** 660 * Creates the chunk provider for this world. Called in the constructor. Retrieves provider from worldProvider? 661 */ 662 protected IChunkProvider createChunkProvider() 663 { 664 IChunkLoader var1 = this.saveHandler.getChunkLoader(this.provider); 665 this.theChunkProviderServer = new ChunkProviderServer(this, var1, this.provider.createChunkGenerator()); 666 return this.theChunkProviderServer; 667 } 668 669 /** 670 * pars: min x,y,z , max x,y,z 671 */ 672 public List getAllTileEntityInBox(int par1, int par2, int par3, int par4, int par5, int par6) 673 { 674 ArrayList var7 = new ArrayList(); 675 676 for(int x = (par1 >> 4); x <= (par4 >> 4); x++) 677 { 678 for(int z = (par3 >> 4); z <= (par6 >> 4); z++) 679 { 680 Chunk chunk = getChunkFromChunkCoords(x, z); 681 if (chunk != null) 682 { 683 for(Object obj : chunk.chunkTileEntityMap.values()) 684 { 685 TileEntity entity = (TileEntity)obj; 686 if (!entity.isInvalid()) 687 { 688 if (entity.xCoord >= par1 && entity.yCoord >= par2 && entity.zCoord >= par3 && 689 entity.xCoord <= par4 && entity.yCoord <= par5 && entity.zCoord <= par6) 690 { 691 var7.add(entity); 692 } 693 } 694 } 695 } 696 } 697 } 698 return var7; 699 } 700 701 /** 702 * Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here. 703 */ 704 public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4) 705 { 706 return super.canMineBlock(par1EntityPlayer, par2, par3, par4); 707 } 708 709 public boolean canMineBlockBody(EntityPlayer par1EntityPlayer, int par2, int par3, int par4) 710 { 711 int var5 = MathHelper.abs_int(par2 - this.worldInfo.getSpawnX()); 712 int var6 = MathHelper.abs_int(par4 - this.worldInfo.getSpawnZ()); 713 714 if (var5 > var6) 715 { 716 var6 = var5; 717 } 718 719 return var6 > mcServer.getSpawnProtectionSize() || this.mcServer.getConfigurationManager().areCommandsAllowed(par1EntityPlayer.username) || this.mcServer.isSinglePlayer(); 720 } 721 722 protected void initialize(WorldSettings par1WorldSettings) 723 { 724 if (this.entityIdMap == null) 725 { 726 this.entityIdMap = new IntHashMap(); 727 } 728 729 if (this.field_73064_N == null) 730 { 731 this.field_73064_N = new HashSet(); 732 } 733 734 if (this.pendingTickListEntries == null) 735 { 736 this.pendingTickListEntries = new TreeSet(); 737 } 738 739 this.createSpawnPosition(par1WorldSettings); 740 super.initialize(par1WorldSettings); 741 } 742 743 /** 744 * creates a spawn position at random within 256 blocks of 0,0 745 */ 746 protected void createSpawnPosition(WorldSettings par1WorldSettings) 747 { 748 if (!this.provider.canRespawnHere()) 749 { 750 this.worldInfo.setSpawnPosition(0, this.provider.getAverageGroundLevel(), 0); 751 } 752 else 753 { 754 this.findingSpawnPoint = true; 755 WorldChunkManager var2 = this.provider.worldChunkMgr; 756 List var3 = var2.getBiomesToSpawnIn(); 757 Random var4 = new Random(this.getSeed()); 758 ChunkPosition var5 = var2.findBiomePosition(0, 0, 256, var3, var4); 759 int var6 = 0; 760 int var7 = this.provider.getAverageGroundLevel(); 761 int var8 = 0; 762 763 if (var5 != null) 764 { 765 var6 = var5.x; 766 var8 = var5.z; 767 } 768 else 769 { 770 System.out.println("Unable to find spawn biome"); 771 } 772 773 int var9 = 0; 774 775 while (!this.provider.canCoordinateBeSpawn(var6, var8)) 776 { 777 var6 += var4.nextInt(64) - var4.nextInt(64); 778 var8 += var4.nextInt(64) - var4.nextInt(64); 779 ++var9; 780 781 if (var9 == 1000) 782 { 783 break; 784 } 785 } 786 787 this.worldInfo.setSpawnPosition(var6, var7, var8); 788 this.findingSpawnPoint = false; 789 790 if (par1WorldSettings.isBonusChestEnabled()) 791 { 792 this.createBonusChest(); 793 } 794 } 795 } 796 797 /** 798 * Creates the bonus chest in the world. 799 */ 800 protected void createBonusChest() 801 { 802 WorldGeneratorBonusChest var1 = new WorldGeneratorBonusChest(ChestGenHooks.getItems(BONUS_CHEST, rand), ChestGenHooks.getCount(BONUS_CHEST, rand)); 803 804 for (int var2 = 0; var2 < 10; ++var2) 805 { 806 int var3 = this.worldInfo.getSpawnX() + this.rand.nextInt(6) - this.rand.nextInt(6); 807 int var4 = this.worldInfo.getSpawnZ() + this.rand.nextInt(6) - this.rand.nextInt(6); 808 int var5 = this.getTopSolidOrLiquidBlock(var3, var4) + 1; 809 810 if (var1.generate(this, this.rand, var3, var5, var4)) 811 { 812 break; 813 } 814 } 815 } 816 817 /** 818 * Gets the hard-coded portal location to use when entering this dimension. 819 */ 820 public ChunkCoordinates getEntrancePortalLocation() 821 { 822 return this.provider.getEntrancePortalLocation(); 823 } 824 825 /** 826 * Saves all chunks to disk while updating progress bar. 827 */ 828 public void saveAllChunks(boolean par1, IProgressUpdate par2IProgressUpdate) throws MinecraftException 829 { 830 if (this.chunkProvider.canSave()) 831 { 832 if (par2IProgressUpdate != null) 833 { 834 par2IProgressUpdate.displayProgressMessage("Saving level"); 835 } 836 837 this.saveLevel(); 838 839 if (par2IProgressUpdate != null) 840 { 841 par2IProgressUpdate.resetProgresAndWorkingMessage("Saving chunks"); 842 } 843 844 this.chunkProvider.saveChunks(par1, par2IProgressUpdate); 845 MinecraftForge.EVENT_BUS.post(new WorldEvent.Save(this)); 846 } 847 } 848 849 /** 850 * Saves the chunks to disk. 851 */ 852 protected void saveLevel() throws MinecraftException 853 { 854 this.checkSessionLock(); 855 this.saveHandler.saveWorldInfoWithPlayer(this.worldInfo, this.mcServer.getConfigurationManager().getTagsFromLastWrite()); 856 this.mapStorage.saveAllData(); 857 this.perWorldStorage.saveAllData(); 858 } 859 860 /** 861 * Start the skin for this entity downloading, if necessary, and increment its reference counter 862 */ 863 protected void obtainEntitySkin(Entity par1Entity) 864 { 865 super.obtainEntitySkin(par1Entity); 866 this.entityIdMap.addKey(par1Entity.entityId, par1Entity); 867 Entity[] var2 = par1Entity.getParts(); 868 869 if (var2 != null) 870 { 871 for (int var3 = 0; var3 < var2.length; ++var3) 872 { 873 this.entityIdMap.addKey(var2[var3].entityId, var2[var3]); 874 } 875 } 876 } 877 878 /** 879 * Decrement the reference counter for this entity's skin image data 880 */ 881 public void releaseEntitySkin(Entity par1Entity) 882 { 883 super.releaseEntitySkin(par1Entity); 884 this.entityIdMap.removeObject(par1Entity.entityId); 885 Entity[] var2 = par1Entity.getParts(); 886 887 if (var2 != null) 888 { 889 for (int var3 = 0; var3 < var2.length; ++var3) 890 { 891 this.entityIdMap.removeObject(var2[var3].entityId); 892 } 893 } 894 } 895 896 /** 897 * Returns the Entity with the given ID, or null if it doesn't exist in this World. 898 */ 899 public Entity getEntityByID(int par1) 900 { 901 return (Entity)this.entityIdMap.lookup(par1); 902 } 903 904 /** 905 * adds a lightning bolt to the list of lightning bolts in this world. 906 */ 907 public boolean addWeatherEffect(Entity par1Entity) 908 { 909 if (super.addWeatherEffect(par1Entity)) 910 { 911 this.mcServer.getConfigurationManager().sendToAllNear(par1Entity.posX, par1Entity.posY, par1Entity.posZ, 512.0D, this.provider.dimensionId, new Packet71Weather(par1Entity)); 912 return true; 913 } 914 else 915 { 916 return false; 917 } 918 } 919 920 /** 921 * sends a Packet 38 (Entity Status) to all tracked players of that entity 922 */ 923 public void setEntityState(Entity par1Entity, byte par2) 924 { 925 Packet38EntityStatus var3 = new Packet38EntityStatus(par1Entity.entityId, par2); 926 this.getEntityTracker().sendPacketToAllAssociatedPlayers(par1Entity, var3); 927 } 928 929 /** 930 * returns a new explosion. Does initiation (at time of writing Explosion is not finished) 931 */ 932 public Explosion newExplosion(Entity par1Entity, double par2, double par4, double par6, float par8, boolean par9, boolean par10) 933 { 934 Explosion var11 = new Explosion(this, par1Entity, par2, par4, par6, par8); 935 var11.isFlaming = par9; 936 var11.isSmoking = par10; 937 var11.doExplosionA(); 938 var11.doExplosionB(false); 939 940 if (!par10) 941 { 942 var11.affectedBlockPositions.clear(); 943 } 944 945 Iterator var12 = this.playerEntities.iterator(); 946 947 while (var12.hasNext()) 948 { 949 EntityPlayer var13 = (EntityPlayer)var12.next(); 950 951 if (var13.getDistanceSq(par2, par4, par6) < 4096.0D) 952 { 953 ((EntityPlayerMP)var13).playerNetServerHandler.sendPacketToPlayer(new Packet60Explosion(par2, par4, par6, par8, var11.affectedBlockPositions, (Vec3)var11.func_77277_b().get(var13))); 954 } 955 } 956 957 return var11; 958 } 959 960 /** 961 * Adds a block event with the given Args to the blockEventCache. During the next tick(), the block specified will 962 * have its onBlockEvent handler called with the given parameters. Args: X,Y,Z, BlockID, EventID, EventParameter 963 */ 964 public void addBlockEvent(int par1, int par2, int par3, int par4, int par5, int par6) 965 { 966 BlockEventData var7 = new BlockEventData(par1, par2, par3, par4, par5, par6); 967 Iterator var8 = this.blockEventCache[this.blockEventCacheIndex].iterator(); 968 BlockEventData var9; 969 970 do 971 { 972 if (!var8.hasNext()) 973 { 974 this.blockEventCache[this.blockEventCacheIndex].add(var7); 975 return; 976 } 977 978 var9 = (BlockEventData)var8.next(); 979 } 980 while (!var9.equals(var7)); 981 } 982 983 /** 984 * Send and apply locally all pending BlockEvents to each player with 64m radius of the event. 985 */ 986 private void sendAndApplyBlockEvents() 987 { 988 while (!this.blockEventCache[this.blockEventCacheIndex].isEmpty()) 989 { 990 int var1 = this.blockEventCacheIndex; 991 this.blockEventCacheIndex ^= 1; 992 Iterator var2 = this.blockEventCache[var1].iterator(); 993 994 while (var2.hasNext()) 995 { 996 BlockEventData var3 = (BlockEventData)var2.next(); 997 998 if (this.onBlockEventReceived(var3)) 999 { 1000 this.mcServer.getConfigurationManager().sendToAllNear((double)var3.getX(), (double)var3.getY(), (double)var3.getZ(), 64.0D, this.provider.dimensionId, new Packet54PlayNoteBlock(var3.getX(), var3.getY(), var3.getZ(), var3.getBlockID(), var3.getEventID(), var3.getEventParameter())); 1001 } 1002 } 1003 1004 this.blockEventCache[var1].clear(); 1005 } 1006 } 1007 1008 /** 1009 * Called to apply a pending BlockEvent to apply to the current world. 1010 */ 1011 private boolean onBlockEventReceived(BlockEventData par1BlockEventData) 1012 { 1013 int var2 = this.getBlockId(par1BlockEventData.getX(), par1BlockEventData.getY(), par1BlockEventData.getZ()); 1014 1015 if (var2 == par1BlockEventData.getBlockID()) 1016 { 1017 Block.blocksList[var2].onBlockEventReceived(this, par1BlockEventData.getX(), par1BlockEventData.getY(), par1BlockEventData.getZ(), par1BlockEventData.getEventID(), par1BlockEventData.getEventParameter()); 1018 return true; 1019 } 1020 else 1021 { 1022 return false; 1023 } 1024 } 1025 1026 /** 1027 * Syncs all changes to disk and wait for completion. 1028 */ 1029 public void flush() 1030 { 1031 this.saveHandler.flush(); 1032 } 1033 1034 /** 1035 * Updates all weather states. 1036 */ 1037 protected void updateWeather() 1038 { 1039 boolean var1 = this.isRaining(); 1040 super.updateWeather(); 1041 1042 if (var1 != this.isRaining()) 1043 { 1044 if (var1) 1045 { 1046 this.mcServer.getConfigurationManager().sendPacketToAllPlayers(new Packet70GameEvent(2, 0)); 1047 } 1048 else 1049 { 1050 this.mcServer.getConfigurationManager().sendPacketToAllPlayers(new Packet70GameEvent(1, 0)); 1051 } 1052 } 1053 } 1054 1055 /** 1056 * Gets the MinecraftServer. 1057 */ 1058 public MinecraftServer getMinecraftServer() 1059 { 1060 return this.mcServer; 1061 } 1062 1063 /** 1064 * Gets the EntityTracker 1065 */ 1066 public EntityTracker getEntityTracker() 1067 { 1068 return this.theEntityTracker; 1069 } 1070 1071 public PlayerManager getPlayerManager() 1072 { 1073 return this.thePlayerManager; 1074 } 1075 1076 public Teleporter func_85176_s() 1077 { 1078 return this.field_85177_Q; 1079 } 1080 1081 public File getChunkSaveLocation() 1082 { 1083 return ((AnvilChunkLoader)theChunkProviderServer.currentChunkLoader).chunkSaveLocation; 1084 } 1085 }