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