001 package net.minecraft.world; 002 003 import cpw.mods.fml.common.Side; 004 import cpw.mods.fml.common.asm.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 time = -System.currentTimeMillis(); 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 if (System.currentTimeMillis() + time <= 4 && doneChunks.add(var4)) { //Limits and evenly distributes the lighting update time 335 var7.updateSkylight(); 336 } 337 this.theProfiler.endStartSection("thunder"); 338 int var8; 339 int var9; 340 int var10; 341 int var11; 342 343 if (provider.canDoLightning(var7) && this.rand.nextInt(100000) == 0 && this.isRaining() && this.isThundering()) 344 { 345 this.updateLCG = this.updateLCG * 3 + 1013904223; 346 var8 = this.updateLCG >> 2; 347 var9 = var5 + (var8 & 15); 348 var10 = var6 + (var8 >> 8 & 15); 349 var11 = this.getPrecipitationHeight(var9, var10); 350 351 if (this.canLightningStrikeAt(var9, var11, var10)) 352 { 353 this.addWeatherEffect(new EntityLightningBolt(this, (double)var9, (double)var11, (double)var10)); 354 this.lastLightningBolt = 2; 355 } 356 } 357 358 this.theProfiler.endStartSection("iceandsnow"); 359 int var13; 360 361 if (provider.canDoRainSnowIce(var7) && this.rand.nextInt(16) == 0) 362 { 363 this.updateLCG = this.updateLCG * 3 + 1013904223; 364 var8 = this.updateLCG >> 2; 365 var9 = var8 & 15; 366 var10 = var8 >> 8 & 15; 367 var11 = this.getPrecipitationHeight(var9 + var5, var10 + var6); 368 369 if (this.isBlockFreezableNaturally(var9 + var5, var11 - 1, var10 + var6)) 370 { 371 this.setBlockWithNotify(var9 + var5, var11 - 1, var10 + var6, Block.ice.blockID); 372 } 373 374 if (this.isRaining() && this.canSnowAt(var9 + var5, var11, var10 + var6)) 375 { 376 this.setBlockWithNotify(var9 + var5, var11, var10 + var6, Block.snow.blockID); 377 } 378 379 if (this.isRaining()) 380 { 381 BiomeGenBase var12 = this.getBiomeGenForCoords(var9 + var5, var10 + var6); 382 383 if (var12.canSpawnLightningBolt()) 384 { 385 var13 = this.getBlockId(var9 + var5, var11 - 1, var10 + var6); 386 387 if (var13 != 0) 388 { 389 Block.blocksList[var13].fillWithRain(this, var9 + var5, var11 - 1, var10 + var6); 390 } 391 } 392 } 393 } 394 395 this.theProfiler.endStartSection("tickTiles"); 396 ExtendedBlockStorage[] var19 = var7.getBlockStorageArray(); 397 var9 = var19.length; 398 399 for (var10 = 0; var10 < var9; ++var10) 400 { 401 ExtendedBlockStorage var21 = var19[var10]; 402 403 if (var21 != null && var21.getNeedsRandomTick()) 404 { 405 for (int var20 = 0; var20 < 3; ++var20) 406 { 407 this.updateLCG = this.updateLCG * 3 + 1013904223; 408 var13 = this.updateLCG >> 2; 409 int var14 = var13 & 15; 410 int var15 = var13 >> 8 & 15; 411 int var16 = var13 >> 16 & 15; 412 int var17 = var21.getExtBlockID(var14, var16, var15); 413 ++var2; 414 Block var18 = Block.blocksList[var17]; 415 416 if (var18 != null && var18.getTickRandomly()) 417 { 418 ++var1; 419 var18.updateTick(this, var14 + var5, var16 + var21.getYLocation(), var15 + var6, this.rand); 420 } 421 } 422 } 423 } 424 425 this.theProfiler.endSection(); 426 } 427 } 428 429 /** 430 * Schedules a tick to a block with a delay (Most commonly the tick rate) 431 */ 432 public void scheduleBlockUpdate(int par1, int par2, int par3, int par4, int par5) 433 { 434 this.func_82740_a(par1, par2, par3, par4, par5, 0); 435 } 436 437 public void func_82740_a(int par1, int par2, int par3, int par4, int par5, int par6) 438 { 439 NextTickListEntry var7 = new NextTickListEntry(par1, par2, par3, par4); 440 boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(var7.xCoord >> 4, var7.zCoord >> 4)); 441 byte var8 = isForced ? (byte)0 : 8; 442 443 if (this.scheduledUpdatesAreImmediate && par4 > 0) 444 { 445 if (Block.blocksList[par4].func_82506_l()) 446 { 447 if (this.checkChunksExist(var7.xCoord - var8, var7.yCoord - var8, var7.zCoord - var8, var7.xCoord + var8, var7.yCoord + var8, var7.zCoord + var8)) 448 { 449 int var9 = this.getBlockId(var7.xCoord, var7.yCoord, var7.zCoord); 450 451 if (var9 == var7.blockID && var9 > 0) 452 { 453 Block.blocksList[var9].updateTick(this, var7.xCoord, var7.yCoord, var7.zCoord, this.rand); 454 } 455 } 456 457 return; 458 } 459 460 par5 = 1; 461 } 462 463 if (this.checkChunksExist(par1 - var8, par2 - var8, par3 - var8, par1 + var8, par2 + var8, par3 + var8)) 464 { 465 if (par4 > 0) 466 { 467 var7.setScheduledTime((long)par5 + this.worldInfo.getWorldTotalTime()); 468 var7.func_82753_a(par6); 469 } 470 471 if (!this.field_73064_N.contains(var7)) 472 { 473 this.field_73064_N.add(var7); 474 this.pendingTickListEntries.add(var7); 475 } 476 } 477 } 478 479 /** 480 * Schedules a block update from the saved information in a chunk. Called when the chunk is loaded. 481 */ 482 public void scheduleBlockUpdateFromLoad(int par1, int par2, int par3, int par4, int par5) 483 { 484 NextTickListEntry var6 = new NextTickListEntry(par1, par2, par3, par4); 485 486 if (par4 > 0) 487 { 488 var6.setScheduledTime((long)par5 + this.worldInfo.getWorldTotalTime()); 489 } 490 491 if (!this.field_73064_N.contains(var6)) 492 { 493 this.field_73064_N.add(var6); 494 this.pendingTickListEntries.add(var6); 495 } 496 } 497 498 /** 499 * Updates (and cleans up) entities and tile entities 500 */ 501 public void updateEntities() 502 { 503 if (this.playerEntities.isEmpty() && getPersistentChunks().isEmpty()) 504 { 505 if (this.updateEntityTick++ >= 1200) 506 { 507 return; 508 } 509 } 510 else 511 { 512 this.resetUpdateEntityTick(); 513 } 514 515 super.updateEntities(); 516 } 517 518 /** 519 * Resets the updateEntityTick field to 0 520 */ 521 public void resetUpdateEntityTick() 522 { 523 this.updateEntityTick = 0; 524 } 525 526 /** 527 * Runs through the list of updates to run and ticks them 528 */ 529 public boolean tickUpdates(boolean par1) 530 { 531 int var2 = this.pendingTickListEntries.size(); 532 533 if (var2 != this.field_73064_N.size()) 534 { 535 throw new IllegalStateException("TickNextTick list out of synch"); 536 } 537 else 538 { 539 if (var2 > 1000) 540 { 541 var2 = 1000; 542 } 543 544 for (int var3 = 0; var3 < var2; ++var3) 545 { 546 NextTickListEntry var4 = (NextTickListEntry)this.pendingTickListEntries.first(); 547 548 if (!par1 && var4.scheduledTime > this.worldInfo.getWorldTotalTime()) 549 { 550 break; 551 } 552 553 this.pendingTickListEntries.remove(var4); 554 this.field_73064_N.remove(var4); 555 boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(var4.xCoord >> 4, var4.zCoord >> 4)); 556 byte var5 = isForced ? (byte)0 : 8; 557 558 if (this.checkChunksExist(var4.xCoord - var5, var4.yCoord - var5, var4.zCoord - var5, var4.xCoord + var5, var4.yCoord + var5, var4.zCoord + var5)) 559 { 560 int var6 = this.getBlockId(var4.xCoord, var4.yCoord, var4.zCoord); 561 562 if (var6 == var4.blockID && var6 > 0) 563 { 564 try 565 { 566 Block.blocksList[var6].updateTick(this, var4.xCoord, var4.yCoord, var4.zCoord, this.rand); 567 } 568 catch (Throwable var13) 569 { 570 CrashReport var8 = CrashReport.func_85055_a(var13, "Exception while ticking a block"); 571 CrashReportCategory var9 = var8.func_85058_a("Block being ticked"); 572 int var10; 573 574 try 575 { 576 var10 = this.getBlockMetadata(var4.xCoord, var4.yCoord, var4.zCoord); 577 } 578 catch (Throwable var12) 579 { 580 var10 = -1; 581 } 582 583 CrashReportCategory.func_85068_a(var9, var4.xCoord, var4.yCoord, var4.zCoord, var6, var10); 584 throw new ReportedException(var8); 585 } 586 } 587 } 588 } 589 590 return !this.pendingTickListEntries.isEmpty(); 591 } 592 } 593 594 public List getPendingBlockUpdates(Chunk par1Chunk, boolean par2) 595 { 596 ArrayList var3 = null; 597 ChunkCoordIntPair var4 = par1Chunk.getChunkCoordIntPair(); 598 int var5 = var4.chunkXPos << 4; 599 int var6 = var5 + 16; 600 int var7 = var4.chunkZPos << 4; 601 int var8 = var7 + 16; 602 Iterator var9 = this.pendingTickListEntries.iterator(); 603 604 while (var9.hasNext()) 605 { 606 NextTickListEntry var10 = (NextTickListEntry)var9.next(); 607 608 if (var10.xCoord >= var5 && var10.xCoord < var6 && var10.zCoord >= var7 && var10.zCoord < var8) 609 { 610 if (par2) 611 { 612 this.field_73064_N.remove(var10); 613 var9.remove(); 614 } 615 616 if (var3 == null) 617 { 618 var3 = new ArrayList(); 619 } 620 621 var3.add(var10); 622 } 623 } 624 625 return var3; 626 } 627 628 /** 629 * Will update the entity in the world if the chunk the entity is in is currently loaded or its forced to update. 630 * Args: entity, forceUpdate 631 */ 632 public void updateEntityWithOptionalForce(Entity par1Entity, boolean par2) 633 { 634 if (!this.mcServer.getCanSpawnAnimals() && (par1Entity instanceof EntityAnimal || par1Entity instanceof EntityWaterMob)) 635 { 636 par1Entity.setDead(); 637 } 638 639 if (!this.mcServer.getCanSpawnNPCs() && par1Entity instanceof INpc) 640 { 641 par1Entity.setDead(); 642 } 643 644 if (!(par1Entity.riddenByEntity instanceof EntityPlayer)) 645 { 646 super.updateEntityWithOptionalForce(par1Entity, par2); 647 } 648 } 649 650 /** 651 * direct call to super.updateEntityWithOptionalForce 652 */ 653 public void uncheckedUpdateEntity(Entity par1Entity, boolean par2) 654 { 655 super.updateEntityWithOptionalForce(par1Entity, par2); 656 } 657 658 /** 659 * Creates the chunk provider for this world. Called in the constructor. Retrieves provider from worldProvider? 660 */ 661 protected IChunkProvider createChunkProvider() 662 { 663 IChunkLoader var1 = this.saveHandler.getChunkLoader(this.provider); 664 this.theChunkProviderServer = new ChunkProviderServer(this, var1, this.provider.createChunkGenerator()); 665 return this.theChunkProviderServer; 666 } 667 668 /** 669 * pars: min x,y,z , max x,y,z 670 */ 671 public List getAllTileEntityInBox(int par1, int par2, int par3, int par4, int par5, int par6) 672 { 673 ArrayList var7 = new ArrayList(); 674 675 for(int x = (par1 >> 4); x <= (par4 >> 4); x++) 676 { 677 for(int z = (par3 >> 4); z <= (par6 >> 4); z++) 678 { 679 Chunk chunk = getChunkFromChunkCoords(x, z); 680 if (chunk != null) 681 { 682 for(Object obj : chunk.chunkTileEntityMap.values()) 683 { 684 TileEntity entity = (TileEntity)obj; 685 if (!entity.isInvalid()) 686 { 687 if (entity.xCoord >= par1 && entity.yCoord >= par2 && entity.zCoord >= par3 && 688 entity.xCoord <= par4 && entity.yCoord <= par5 && entity.zCoord <= par6) 689 { 690 var7.add(entity); 691 } 692 } 693 } 694 } 695 } 696 } 697 return var7; 698 } 699 700 /** 701 * Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here. 702 */ 703 public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4) 704 { 705 return super.canMineBlock(par1EntityPlayer, par2, par3, par4); 706 } 707 708 public boolean canMineBlockBody(EntityPlayer par1EntityPlayer, int par2, int par3, int par4) 709 { 710 int var5 = MathHelper.abs_int(par2 - this.worldInfo.getSpawnX()); 711 int var6 = MathHelper.abs_int(par4 - this.worldInfo.getSpawnZ()); 712 713 if (var5 > var6) 714 { 715 var6 = var5; 716 } 717 718 return var6 > mcServer.getSpawnProtectionSize() || this.mcServer.getConfigurationManager().areCommandsAllowed(par1EntityPlayer.username) || this.mcServer.isSinglePlayer(); 719 } 720 721 protected void initialize(WorldSettings par1WorldSettings) 722 { 723 if (this.entityIdMap == null) 724 { 725 this.entityIdMap = new IntHashMap(); 726 } 727 728 if (this.field_73064_N == null) 729 { 730 this.field_73064_N = new HashSet(); 731 } 732 733 if (this.pendingTickListEntries == null) 734 { 735 this.pendingTickListEntries = new TreeSet(); 736 } 737 738 this.createSpawnPosition(par1WorldSettings); 739 super.initialize(par1WorldSettings); 740 } 741 742 /** 743 * creates a spawn position at random within 256 blocks of 0,0 744 */ 745 protected void createSpawnPosition(WorldSettings par1WorldSettings) 746 { 747 if (!this.provider.canRespawnHere()) 748 { 749 this.worldInfo.setSpawnPosition(0, this.provider.getAverageGroundLevel(), 0); 750 } 751 else 752 { 753 this.findingSpawnPoint = true; 754 WorldChunkManager var2 = this.provider.worldChunkMgr; 755 List var3 = var2.getBiomesToSpawnIn(); 756 Random var4 = new Random(this.getSeed()); 757 ChunkPosition var5 = var2.findBiomePosition(0, 0, 256, var3, var4); 758 int var6 = 0; 759 int var7 = this.provider.getAverageGroundLevel(); 760 int var8 = 0; 761 762 if (var5 != null) 763 { 764 var6 = var5.x; 765 var8 = var5.z; 766 } 767 else 768 { 769 System.out.println("Unable to find spawn biome"); 770 } 771 772 int var9 = 0; 773 774 while (!this.provider.canCoordinateBeSpawn(var6, var8)) 775 { 776 var6 += var4.nextInt(64) - var4.nextInt(64); 777 var8 += var4.nextInt(64) - var4.nextInt(64); 778 ++var9; 779 780 if (var9 == 1000) 781 { 782 break; 783 } 784 } 785 786 this.worldInfo.setSpawnPosition(var6, var7, var8); 787 this.findingSpawnPoint = false; 788 789 if (par1WorldSettings.isBonusChestEnabled()) 790 { 791 this.createBonusChest(); 792 } 793 } 794 } 795 796 /** 797 * Creates the bonus chest in the world. 798 */ 799 protected void createBonusChest() 800 { 801 WorldGeneratorBonusChest var1 = new WorldGeneratorBonusChest(ChestGenHooks.getItems(BONUS_CHEST), ChestGenHooks.getCount(BONUS_CHEST, rand)); 802 803 for (int var2 = 0; var2 < 10; ++var2) 804 { 805 int var3 = this.worldInfo.getSpawnX() + this.rand.nextInt(6) - this.rand.nextInt(6); 806 int var4 = this.worldInfo.getSpawnZ() + this.rand.nextInt(6) - this.rand.nextInt(6); 807 int var5 = this.getTopSolidOrLiquidBlock(var3, var4) + 1; 808 809 if (var1.generate(this, this.rand, var3, var5, var4)) 810 { 811 break; 812 } 813 } 814 } 815 816 /** 817 * Gets the hard-coded portal location to use when entering this dimension. 818 */ 819 public ChunkCoordinates getEntrancePortalLocation() 820 { 821 return this.provider.getEntrancePortalLocation(); 822 } 823 824 /** 825 * Saves all chunks to disk while updating progress bar. 826 */ 827 public void saveAllChunks(boolean par1, IProgressUpdate par2IProgressUpdate) throws MinecraftException 828 { 829 if (this.chunkProvider.canSave()) 830 { 831 if (par2IProgressUpdate != null) 832 { 833 par2IProgressUpdate.displayProgressMessage("Saving level"); 834 } 835 836 this.saveLevel(); 837 838 if (par2IProgressUpdate != null) 839 { 840 par2IProgressUpdate.resetProgresAndWorkingMessage("Saving chunks"); 841 } 842 843 this.chunkProvider.saveChunks(par1, par2IProgressUpdate); 844 MinecraftForge.EVENT_BUS.post(new WorldEvent.Save(this)); 845 } 846 } 847 848 /** 849 * Saves the chunks to disk. 850 */ 851 protected void saveLevel() throws MinecraftException 852 { 853 this.checkSessionLock(); 854 this.saveHandler.saveWorldInfoWithPlayer(this.worldInfo, this.mcServer.getConfigurationManager().getTagsFromLastWrite()); 855 this.mapStorage.saveAllData(); 856 this.perWorldStorage.saveAllData(); 857 } 858 859 /** 860 * Start the skin for this entity downloading, if necessary, and increment its reference counter 861 */ 862 protected void obtainEntitySkin(Entity par1Entity) 863 { 864 super.obtainEntitySkin(par1Entity); 865 this.entityIdMap.addKey(par1Entity.entityId, par1Entity); 866 Entity[] var2 = par1Entity.getParts(); 867 868 if (var2 != null) 869 { 870 for (int var3 = 0; var3 < var2.length; ++var3) 871 { 872 this.entityIdMap.addKey(var2[var3].entityId, var2[var3]); 873 } 874 } 875 } 876 877 /** 878 * Decrement the reference counter for this entity's skin image data 879 */ 880 protected void releaseEntitySkin(Entity par1Entity) 881 { 882 super.releaseEntitySkin(par1Entity); 883 this.entityIdMap.removeObject(par1Entity.entityId); 884 Entity[] var2 = par1Entity.getParts(); 885 886 if (var2 != null) 887 { 888 for (int var3 = 0; var3 < var2.length; ++var3) 889 { 890 this.entityIdMap.removeObject(var2[var3].entityId); 891 } 892 } 893 } 894 895 /** 896 * Returns the Entity with the given ID, or null if it doesn't exist in this World. 897 */ 898 public Entity getEntityByID(int par1) 899 { 900 return (Entity)this.entityIdMap.lookup(par1); 901 } 902 903 /** 904 * adds a lightning bolt to the list of lightning bolts in this world. 905 */ 906 public boolean addWeatherEffect(Entity par1Entity) 907 { 908 if (super.addWeatherEffect(par1Entity)) 909 { 910 this.mcServer.getConfigurationManager().sendToAllNear(par1Entity.posX, par1Entity.posY, par1Entity.posZ, 512.0D, this.provider.dimensionId, new Packet71Weather(par1Entity)); 911 return true; 912 } 913 else 914 { 915 return false; 916 } 917 } 918 919 /** 920 * sends a Packet 38 (Entity Status) to all tracked players of that entity 921 */ 922 public void setEntityState(Entity par1Entity, byte par2) 923 { 924 Packet38EntityStatus var3 = new Packet38EntityStatus(par1Entity.entityId, par2); 925 this.getEntityTracker().sendPacketToAllAssociatedPlayers(par1Entity, var3); 926 } 927 928 /** 929 * returns a new explosion. Does initiation (at time of writing Explosion is not finished) 930 */ 931 public Explosion newExplosion(Entity par1Entity, double par2, double par4, double par6, float par8, boolean par9, boolean par10) 932 { 933 Explosion var11 = new Explosion(this, par1Entity, par2, par4, par6, par8); 934 var11.isFlaming = par9; 935 var11.isSmoking = par10; 936 var11.doExplosionA(); 937 var11.doExplosionB(false); 938 939 if (!par10) 940 { 941 var11.affectedBlockPositions.clear(); 942 } 943 944 Iterator var12 = this.playerEntities.iterator(); 945 946 while (var12.hasNext()) 947 { 948 EntityPlayer var13 = (EntityPlayer)var12.next(); 949 950 if (var13.getDistanceSq(par2, par4, par6) < 4096.0D) 951 { 952 ((EntityPlayerMP)var13).playerNetServerHandler.sendPacketToPlayer(new Packet60Explosion(par2, par4, par6, par8, var11.affectedBlockPositions, (Vec3)var11.func_77277_b().get(var13))); 953 } 954 } 955 956 return var11; 957 } 958 959 /** 960 * Adds a block event with the given Args to the blockEventCache. During the next tick(), the block specified will 961 * have its onBlockEvent handler called with the given parameters. Args: X,Y,Z, BlockID, EventID, EventParameter 962 */ 963 public void addBlockEvent(int par1, int par2, int par3, int par4, int par5, int par6) 964 { 965 BlockEventData var7 = new BlockEventData(par1, par2, par3, par4, par5, par6); 966 Iterator var8 = this.blockEventCache[this.blockEventCacheIndex].iterator(); 967 BlockEventData var9; 968 969 do 970 { 971 if (!var8.hasNext()) 972 { 973 this.blockEventCache[this.blockEventCacheIndex].add(var7); 974 return; 975 } 976 977 var9 = (BlockEventData)var8.next(); 978 } 979 while (!var9.equals(var7)); 980 } 981 982 /** 983 * Send and apply locally all pending BlockEvents to each player with 64m radius of the event. 984 */ 985 private void sendAndApplyBlockEvents() 986 { 987 while (!this.blockEventCache[this.blockEventCacheIndex].isEmpty()) 988 { 989 int var1 = this.blockEventCacheIndex; 990 this.blockEventCacheIndex ^= 1; 991 Iterator var2 = this.blockEventCache[var1].iterator(); 992 993 while (var2.hasNext()) 994 { 995 BlockEventData var3 = (BlockEventData)var2.next(); 996 997 if (this.onBlockEventReceived(var3)) 998 { 999 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())); 1000 } 1001 } 1002 1003 this.blockEventCache[var1].clear(); 1004 } 1005 } 1006 1007 /** 1008 * Called to apply a pending BlockEvent to apply to the current world. 1009 */ 1010 private boolean onBlockEventReceived(BlockEventData par1BlockEventData) 1011 { 1012 int var2 = this.getBlockId(par1BlockEventData.getX(), par1BlockEventData.getY(), par1BlockEventData.getZ()); 1013 1014 if (var2 == par1BlockEventData.getBlockID()) 1015 { 1016 Block.blocksList[var2].onBlockEventReceived(this, par1BlockEventData.getX(), par1BlockEventData.getY(), par1BlockEventData.getZ(), par1BlockEventData.getEventID(), par1BlockEventData.getEventParameter()); 1017 return true; 1018 } 1019 else 1020 { 1021 return false; 1022 } 1023 } 1024 1025 /** 1026 * Syncs all changes to disk and wait for completion. 1027 */ 1028 public void flush() 1029 { 1030 this.saveHandler.flush(); 1031 } 1032 1033 /** 1034 * Updates all weather states. 1035 */ 1036 protected void updateWeather() 1037 { 1038 boolean var1 = this.isRaining(); 1039 super.updateWeather(); 1040 1041 if (var1 != this.isRaining()) 1042 { 1043 if (var1) 1044 { 1045 this.mcServer.getConfigurationManager().sendPacketToAllPlayers(new Packet70GameEvent(2, 0)); 1046 } 1047 else 1048 { 1049 this.mcServer.getConfigurationManager().sendPacketToAllPlayers(new Packet70GameEvent(1, 0)); 1050 } 1051 } 1052 } 1053 1054 /** 1055 * Gets the MinecraftServer. 1056 */ 1057 public MinecraftServer getMinecraftServer() 1058 { 1059 return this.mcServer; 1060 } 1061 1062 /** 1063 * Gets the EntityTracker 1064 */ 1065 public EntityTracker getEntityTracker() 1066 { 1067 return this.theEntityTracker; 1068 } 1069 1070 public PlayerManager getPlayerManager() 1071 { 1072 return this.thePlayerManager; 1073 } 1074 1075 public Teleporter func_85176_s() 1076 { 1077 return this.field_85177_Q; 1078 } 1079 1080 public File getChunkSaveLocation() 1081 { 1082 return ((AnvilChunkLoader)theChunkProviderServer.currentChunkLoader).chunkSaveLocation; 1083 } 1084 }