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