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.itemID, 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.itemID, 0, 1, 1, 3), new WeightedRandomChestContent(Item.axeWood.itemID, 0, 1, 1, 5), new WeightedRandomChestContent(Item.pickaxeStone.itemID, 0, 1, 1, 3), new WeightedRandomChestContent(Item.pickaxeWood.itemID, 0, 1, 1, 5), new WeightedRandomChestContent(Item.appleRed.itemID, 0, 2, 3, 5), new WeightedRandomChestContent(Item.bread.itemID, 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 }