--- ../src-base/minecraft/net/minecraft/world/WorldServer.java +++ ../src-work/minecraft/net/minecraft/world/WorldServer.java @@ -1,8 +1,11 @@ package net.minecraft.world; import com.google.common.collect.Lists; + +import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; + import java.io.File; import java.util.ArrayList; import java.util.HashSet; @@ -11,6 +14,7 @@ import java.util.Random; import java.util.Set; import java.util.TreeSet; + import net.minecraft.block.Block; import net.minecraft.block.BlockEventData; import net.minecraft.block.material.Material; @@ -56,10 +60,13 @@ import net.minecraft.world.chunk.storage.IChunkLoader; import net.minecraft.world.gen.ChunkProviderServer; import net.minecraft.world.gen.feature.WorldGeneratorBonusChest; +import net.minecraft.world.storage.DerivedWorldInfo; import net.minecraft.world.storage.ISaveHandler; +import net.minecraftforge.cauldron.configuration.CauldronConfig; import net.minecraftforge.common.ChestGenHooks; import static net.minecraftforge.common.ChestGenHooks.BONUS_CHEST; import net.minecraftforge.common.DimensionManager; +import net.minecraftforge.common.ForgeModContainer; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.event.world.WorldEvent; @@ -67,11 +74,26 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; + +// CraftBukkit start +import net.minecraft.block.ITileEntityProvider; +import net.minecraft.block.BlockJukebox; +import net.minecraft.tileentity.*; + +import org.bukkit.WeatherType; +import org.bukkit.block.BlockState; +import org.bukkit.craftbukkit.util.LongHash; +import org.bukkit.event.block.BlockFormEvent; +import org.bukkit.event.weather.LightningStrikeEvent; +import org.bukkit.event.weather.ThunderChangeEvent; +import org.bukkit.event.weather.WeatherChangeEvent; +// CraftBukkit end + public class WorldServer extends World { private static final Logger logger = LogManager.getLogger(); private final MinecraftServer mcServer; - private final EntityTracker theEntityTracker; + public EntityTracker theEntityTracker; // CraftBukkit - private final -> public private final PlayerManager thePlayerManager; private Set pendingTickListEntriesHashSet; private TreeSet pendingTickListEntriesTreeSet; @@ -92,9 +114,13 @@ protected Set doneChunks = new HashSet(); public List customTeleporters = new ArrayList(); + // CraftBukkit start + public final int dimension; + public WorldServer(MinecraftServer p_i45284_1_, ISaveHandler p_i45284_2_, String p_i45284_3_, int p_i45284_4_, WorldSettings p_i45284_5_, Profiler p_i45284_6_) { super(p_i45284_2_, p_i45284_3_, p_i45284_5_, WorldProvider.getProviderForDimension(p_i45284_4_), p_i45284_6_); + this.dimension = p_i45284_4_; this.mcServer = p_i45284_1_; this.theEntityTracker = new EntityTracker(this); this.thePlayerManager = new PlayerManager(this); @@ -103,15 +129,17 @@ { this.entityIdMap = new IntHashMap(); } + + if (this.blockUpdatesTracker == null) this.blockUpdatesTracker = new kcauldron.BlockUpdatesTracker(this); if (this.pendingTickListEntriesHashSet == null) { - this.pendingTickListEntriesHashSet = new HashSet(); + this.pendingTickListEntriesHashSet = blockUpdatesTracker.hashSet; } if (this.pendingTickListEntriesTreeSet == null) { - this.pendingTickListEntriesTreeSet = new TreeSet(); + this.pendingTickListEntriesTreeSet = blockUpdatesTracker.treeSet; } this.worldTeleporter = new Teleporter(this); @@ -124,6 +152,49 @@ this.mapStorage.setData("scoreboard", scoreboardsavedata); } + scoreboardsavedata.func_96499_a(this.worldScoreboard); + ((ServerScoreboard) this.worldScoreboard).func_96547_a(scoreboardsavedata); + } + + // Add env and gen to constructor + public WorldServer(MinecraftServer p_i45284_1_, ISaveHandler p_i45284_2_, String p_i45284_3_, int p_i45284_4_, WorldSettings p_i45284_5_, + Profiler p_i45284_6_, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) + { + super(p_i45284_2_, p_i45284_3_, p_i45284_5_, WorldProvider.getProviderForDimension(p_i45284_4_), p_i45284_6_, gen, env); + this.dimension = p_i45284_4_; + this.pvpMode = p_i45284_1_.isPVPEnabled(); + // CraftBukkit end + this.mcServer = p_i45284_1_; + this.theEntityTracker = new EntityTracker(this); + this.thePlayerManager = new PlayerManager(this, spigotConfig.viewDistance); // Spigot + + if (this.entityIdMap == null) + { + this.entityIdMap = new IntHashMap(); + } + + if (this.blockUpdatesTracker == null) this.blockUpdatesTracker = new kcauldron.BlockUpdatesTracker(this); + + if (this.pendingTickListEntriesHashSet == null) + { + this.pendingTickListEntriesHashSet = blockUpdatesTracker.hashSet; + } + + if (this.pendingTickListEntriesTreeSet == null) + { + this.pendingTickListEntriesTreeSet = blockUpdatesTracker.treeSet; + } + + this.worldTeleporter = new org.bukkit.craftbukkit.CraftTravelAgent(this); // CraftBukkit + this.worldScoreboard = new ServerScoreboard(p_i45284_1_); + ScoreboardSaveData scoreboardsavedata = (ScoreboardSaveData) this.mapStorage.loadData(ScoreboardSaveData.class, "scoreboard"); + + if (scoreboardsavedata == null) + { + scoreboardsavedata = new ScoreboardSaveData(); + this.mapStorage.setData("scoreboard", scoreboardsavedata); + } + if (!(this instanceof WorldServerMulti)) //Forge: We fix the global mapStorage, which causes us to share scoreboards early. So don't associate the save data with the temporary scoreboard { scoreboardsavedata.func_96499_a(this.worldScoreboard); @@ -132,6 +203,32 @@ DimensionManager.setWorld(p_i45284_4_, this); } + public WorldServer(MinecraftServer minecraftServer, ISaveHandler saveHandler, String par2String, WorldProvider provider, WorldSettings par4WorldSettings, + Profiler theProfiler) + { + super(saveHandler, par2String, provider, par4WorldSettings, theProfiler); + this.dimension = provider.dimensionId; + this.pvpMode = minecraftServer.isPVPEnabled(); + this.mcServer = minecraftServer; + this.theEntityTracker = null; + this.thePlayerManager = null; + this.worldTeleporter = null; + this.blockUpdatesTracker = null; + } + + private boolean canSpawn(int x, int z) + { + if (this.generator != null) + { + return this.generator.canSpawn(this.getWorld(), x, z); + } + else + { + return this.provider.canCoordinateBeSpawn(x, z); + } + } + // CraftBukkit end + public void tick() { super.tick(); @@ -155,12 +252,19 @@ } this.theProfiler.startSection("mobSpawner"); + // CraftBukkit start - Only call spawner if we have players online and the world allows for mobs or animals + long time = this.worldInfo.getWorldTotalTime(); - if (this.getGameRules().getGameRuleBooleanValue("doMobSpawning")) + if (this.getGameRules().getGameRuleBooleanValue("doMobSpawning") && (this.spawnHostileMobs || this.spawnPeacefulMobs) && (this instanceof WorldServer && this.playerEntities.size() > 0)) { - this.animalSpawner.findChunksForSpawning(this, this.spawnHostileMobs, this.spawnPeacefulMobs, this.worldInfo.getWorldTotalTime() % 400L == 0L); + timings.mobSpawn.startTiming(); // Spigot + this.animalSpawner.findChunksForSpawning(this, this.spawnHostileMobs + && (this.ticksPerMonsterSpawns != 0 && time % this.ticksPerMonsterSpawns == 0L), this.spawnPeacefulMobs + && (this.ticksPerAnimalSpawns != 0 && time % this.ticksPerAnimalSpawns == 0L), this.worldInfo.getWorldTotalTime() % 400L == 0L); + timings.mobSpawn.stopTiming(); // Spigot } - + // CraftBukkit end + timings.doChunkUnload.startTiming(); // Spigot this.theProfiler.endStartSection("chunkSource"); this.chunkProvider.unloadQueuedChunks(); int j = this.calculateSkylightSubtracted(1.0F); @@ -170,30 +274,47 @@ this.skylightSubtracted = j; } - this.worldInfo.incrementTotalWorldTime(this.worldInfo.getWorldTotalTime() + 1L); + this.worldInfo.tick(); if (this.getGameRules().getGameRuleBooleanValue("doDaylightCycle")) { this.worldInfo.setWorldTime(this.worldInfo.getWorldTime() + 1L); } + timings.doChunkUnload.stopTiming(); // Spigot this.theProfiler.endStartSection("tickPending"); + timings.doTickPending.startTiming(); // Spigot this.tickUpdates(false); + timings.doTickPending.stopTiming(); // Spigot this.theProfiler.endStartSection("tickBlocks"); + timings.doTickTiles.startTiming(); // Spigot this.func_147456_g(); + timings.doTickTiles.stopTiming(); // Spigot this.theProfiler.endStartSection("chunkMap"); + timings.doChunkMap.startTiming(); // Spigot this.thePlayerManager.updatePlayerInstances(); + timings.doChunkMap.stopTiming(); // Spigot this.theProfiler.endStartSection("village"); + timings.doVillages.startTiming(); // Spigot this.villageCollectionObj.tick(); this.villageSiegeObj.tick(); + timings.doVillages.stopTiming(); // Spigot this.theProfiler.endStartSection("portalForcer"); + timings.doPortalForcer.startTiming(); // Spigot this.worldTeleporter.removeStalePortalLocations(this.getTotalWorldTime()); for (Teleporter tele : customTeleporters) { tele.removeStalePortalLocations(getTotalWorldTime()); } + timings.doPortalForcer.stopTiming(); // Spigot this.theProfiler.endSection(); + timings.doSounds.startTiming(); // Spigot this.func_147488_Z(); + timings.doSounds.stopTiming(); // Spigot + + timings.doChunkGC.startTiming(); // Spigot + this.getWorld().processChunkGC(); // CraftBukkit + timings.doChunkGC.stopTiming(); // Spigot } public BiomeGenBase.SpawnListEntry spawnRandomCreature(EnumCreatureType p_73057_1_, int p_73057_2_, int p_73057_3_, int p_73057_4_) @@ -212,7 +333,7 @@ { EntityPlayer entityplayer = (EntityPlayer)iterator.next(); - if (!entityplayer.isPlayerSleeping()) + if (!entityplayer.isPlayerSleeping() && !entityplayer.fauxSleeping) // CraftBukkit { this.allPlayersSleeping = false; break; @@ -240,7 +361,25 @@ private void resetRainAndThunder() { - provider.resetRainAndThunder(); + // CraftBukkit start + WeatherChangeEvent weather = new WeatherChangeEvent(this.getWorld(), false); + this.getServer().getPluginManager().callEvent(weather); + ThunderChangeEvent thunder = new ThunderChangeEvent(this.getWorld(), false); + this.getServer().getPluginManager().callEvent(thunder); + + if (!weather.isCancelled()) + { + this.worldInfo.setRainTime(0); + this.worldInfo.setRaining(false); + } + + if (!thunder.isCancelled()) + { + this.worldInfo.setThunderTime(0); + this.worldInfo.setThundering(false); + } + // CraftBukkit end + if (!weather.isCancelled() && !thunder.isCancelled()) provider.resetRainAndThunder(); // Cauldron } public boolean areAllPlayersAsleep() @@ -248,19 +387,26 @@ if (this.allPlayersSleeping && !this.isRemote) { Iterator iterator = this.playerEntities.iterator(); + // CraftBukkit - This allows us to assume that some people are in bed but not really, allowing time to pass in spite of AFKers + boolean foundActualSleepers = false; EntityPlayer entityplayer; do { if (!iterator.hasNext()) { - return true; + return foundActualSleepers; // CraftBukkit } entityplayer = (EntityPlayer)iterator.next(); + // CraftBukkit start + if (entityplayer.isPlayerFullyAsleep()) + { + foundActualSleepers = true; + } } - while (entityplayer.isPlayerFullyAsleep()); - + while (entityplayer.isPlayerFullyAsleep() || entityplayer.fauxSleeping); + // CraftBukkit end return false; } else @@ -302,15 +448,29 @@ super.func_147456_g(); int i = 0; int j = 0; - Iterator iterator = this.activeChunkSet.iterator(); + // Iterator iterator = this.activeChunkSet.iterator(); - while (iterator.hasNext()) + // Spigot start + for (gnu.trove.iterator.TLongShortIterator iter = activeChunkSet_CB.iterator(); iter.hasNext();) { - ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair)iterator.next(); - int k = chunkcoordintpair.chunkXPos * 16; - int l = chunkcoordintpair.chunkZPos * 16; + iter.advance(); + long chunkCoord = iter.key(); + int chunkX = World.keyToX(chunkCoord); + int chunkZ = World.keyToZ(chunkCoord); + // If unloaded, or in process of being unloaded, drop it + if ((!this.chunkExists(chunkX, chunkZ)) || (this.theChunkProviderServer.chunksToUnload.contains(chunkX, chunkZ))) + { + activeChunkSet.remove(new ChunkCoordIntPair(chunkX, chunkZ)); // Cauldron - vanilla compatibility + iter.remove(); + continue; + } + // Spigot end + // ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator.next(); + int k = chunkX * 16; + int l = chunkZ * 16; + this.theProfiler.startSection("getChunk"); - Chunk chunk = this.getChunkFromChunkCoords(chunkcoordintpair.chunkXPos, chunkcoordintpair.chunkZPos); + Chunk chunk = this.getChunkFromChunkCoords(chunkX, chunkZ); this.func_147467_a(k, l, chunk); this.theProfiler.endStartSection("tickChunk"); chunk.func_150804_b(false); @@ -346,12 +506,32 @@ if (this.isBlockFreezableNaturally(j1 + k, l1 - 1, k1 + l)) { - this.setBlock(j1 + k, l1 - 1, k1 + l, Blocks.ice); + // CraftBukkit start + BlockState blockState = this.getWorld().getBlockAt(j1 + k, l1 - 1, k1 + l).getState(); + blockState.setTypeId(Block.getIdFromBlock(Blocks.ice)); + BlockFormEvent iceBlockForm = new BlockFormEvent(blockState.getBlock(), blockState); + this.getServer().getPluginManager().callEvent(iceBlockForm); + + if (!iceBlockForm.isCancelled()) + { + blockState.update(true); + } + // CraftBukkit end } if (this.isRaining() && this.func_147478_e(j1 + k, l1, k1 + l, true)) { - this.setBlock(j1 + k, l1, k1 + l, Blocks.snow_layer); + // CraftBukkit start + BlockState blockState = this.getWorld().getBlockAt(j1 + k, l1, k1 + l).getState(); + blockState.setTypeId(Block.getIdFromBlock(Blocks.snow_layer)); + BlockFormEvent snow = new BlockFormEvent(blockState.getBlock(), blockState); + this.getServer().getPluginManager().callEvent(snow); + + if (!snow.isCancelled()) + { + blockState.update(true); + } + // CraftBukkit end } if (this.isRaining()) @@ -388,6 +568,7 @@ if (block.getTickRandomly()) { ++i; + this.growthOdds = (iter.value() < 1) ? this.modifiedOdds : 100; // Spigot - grow fast if no players are in this chunk (value = player count) block.updateTick(this, j2 + k, l2 + extendedblockstorage.getYLocation(), k2 + l, this.rand); } } @@ -396,12 +577,19 @@ this.theProfiler.endSection(); } + // Spigot Start + if (this.getSpigotConfig().clearChunksOnTick) // Cauldron + { + activeChunkSet_CB.clear(); + activeChunkSet.clear(); // Cauldron + } + // Spigot End } public boolean isBlockTickScheduledThisTick(int p_147477_1_, int p_147477_2_, int p_147477_3_, Block p_147477_4_) { - NextTickListEntry nextticklistentry = new NextTickListEntry(p_147477_1_, p_147477_2_, p_147477_3_, p_147477_4_); - return this.pendingTickListEntriesThisTick.contains(nextticklistentry); + for (kcauldron.BlockUpdateEntry entry : (Iterable) pendingTickListEntriesThisTick) if (entry.x == p_147477_1_ && entry.y == p_147477_2_ && entry.z == p_147477_3_ && entry.block == p_147477_4_) return true; + return false; } public void scheduleBlockUpdate(int p_147464_1_, int p_147464_2_, int p_147464_3_, Block p_147464_4_, int p_147464_5_) @@ -411,70 +599,29 @@ public void scheduleBlockUpdateWithPriority(int p_147454_1_, int p_147454_2_, int p_147454_3_, Block p_147454_4_, int p_147454_5_, int p_147454_6_) { - NextTickListEntry nextticklistentry = new NextTickListEntry(p_147454_1_, p_147454_2_, p_147454_3_, p_147454_4_); - //Keeping here as a note for future when it may be restored. - //boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(nextticklistentry.xCoord >> 4, nextticklistentry.zCoord >> 4)); - //byte b0 = isForced ? 0 : 8; - byte b0 = 0; - - if (this.scheduledUpdatesAreImmediate && p_147454_4_.getMaterial() != Material.air) - { - if (p_147454_4_.func_149698_L()) - { - b0 = 8; - - if (this.checkChunksExist(nextticklistentry.xCoord - b0, nextticklistentry.yCoord - b0, nextticklistentry.zCoord - b0, nextticklistentry.xCoord + b0, nextticklistentry.yCoord + b0, nextticklistentry.zCoord + b0)) - { - Block block1 = this.getBlock(nextticklistentry.xCoord, nextticklistentry.yCoord, nextticklistentry.zCoord); - - if (block1.getMaterial() != Material.air && block1 == nextticklistentry.func_151351_a()) - { - block1.updateTick(this, nextticklistentry.xCoord, nextticklistentry.yCoord, nextticklistentry.zCoord, this.rand); - } + if (this.scheduledUpdatesAreImmediate && p_147454_4_.getMaterial() != Material.air) { + if (p_147454_4_.func_149698_L()) { + if (checkChunksExist(p_147454_1_ - 8, p_147454_2_ - 8, p_147454_3_ - 8, p_147454_1_ + 8, p_147454_2_ + 8, p_147454_3_ + 8)) { + Block block = getBlock(p_147454_1_, p_147454_2_, p_147454_3_); + if (block.getMaterial() != Material.air && block == p_147454_4_) + block.updateTick(this, p_147454_1_, p_147454_2_, p_147454_3_, rand); } - return; } - p_147454_5_ = 1; } - - if (this.checkChunksExist(p_147454_1_ - b0, p_147454_2_ - b0, p_147454_3_ - b0, p_147454_1_ + b0, p_147454_2_ + b0, p_147454_3_ + b0)) - { - if (p_147454_4_.getMaterial() != Material.air) - { - nextticklistentry.setScheduledTime((long)p_147454_5_ + this.worldInfo.getWorldTotalTime()); - nextticklistentry.setPriority(p_147454_6_); - } - - if (!this.pendingTickListEntriesHashSet.contains(nextticklistentry)) - { - this.pendingTickListEntriesHashSet.add(nextticklistentry); - this.pendingTickListEntriesTreeSet.add(nextticklistentry); - } - } + if (getChunkIfLoaded(p_147454_1_ >> 4, p_147454_3_ >> 4) != null) + blockUpdatesTracker.allocateEntry(p_147454_1_, p_147454_2_, p_147454_3_, p_147454_6_, p_147454_5_ + this.worldInfo.getWorldTotalTime(), p_147454_4_); } public void func_147446_b(int p_147446_1_, int p_147446_2_, int p_147446_3_, Block p_147446_4_, int p_147446_5_, int p_147446_6_) { - NextTickListEntry nextticklistentry = new NextTickListEntry(p_147446_1_, p_147446_2_, p_147446_3_, p_147446_4_); - nextticklistentry.setPriority(p_147446_6_); - - if (p_147446_4_.getMaterial() != Material.air) - { - nextticklistentry.setScheduledTime((long)p_147446_5_ + this.worldInfo.getWorldTotalTime()); - } - - if (!this.pendingTickListEntriesHashSet.contains(nextticklistentry)) - { - this.pendingTickListEntriesHashSet.add(nextticklistentry); - this.pendingTickListEntriesTreeSet.add(nextticklistentry); - } + blockUpdatesTracker.allocateEntry(p_147446_1_, p_147446_2_, p_147446_3_, p_147446_6_, p_147446_5_ + this.worldInfo.getWorldTotalTime(), p_147446_4_); } public void updateEntities() { - if (this.playerEntities.isEmpty() && getPersistentChunks().isEmpty()) + if (this.playerEntities.isEmpty() && getPersistentChunks().isEmpty()) // Cauldron Use Forge logic here { if (this.updateEntityTick++ >= 1200) { @@ -487,6 +634,7 @@ } super.updateEntities(); + spigotConfig.currentPrimedTnt = 0; // Spigot } public void resetUpdateEntityTick() @@ -496,33 +644,40 @@ public boolean tickUpdates(boolean p_72955_1_) { - int i = this.pendingTickListEntriesTreeSet.size(); + int i = blockUpdatesTracker.size(); - if (i != this.pendingTickListEntriesHashSet.size()) + //if (i != this.pendingTickListEntriesHashSet.size()) + //{ + // throw new IllegalStateException("TickNextTick list out of synch"); + //} + //else { - throw new IllegalStateException("TickNextTick list out of synch"); - } - else - { if (i > 1000) { - i = 1000; + // CraftBukkit start - If the server has too much to process over time, try to alleviate that + if (i > 20 * 1000) + { + i = i / 20; + } + else + { + i = 1000; + } + // CraftBukkit end } this.theProfiler.startSection("cleaning"); - NextTickListEntry nextticklistentry; + kcauldron.BlockUpdateEntry nextticklistentry; for (int j = 0; j < i; ++j) { - nextticklistentry = (NextTickListEntry)this.pendingTickListEntriesTreeSet.first(); - - if (!p_72955_1_ && nextticklistentry.scheduledTime > this.worldInfo.getWorldTotalTime()) + nextticklistentry = blockUpdatesTracker.peek(); + Chunk chunk = getChunkIfLoaded(nextticklistentry.x >> 4, nextticklistentry.z >> 4); + if (!p_72955_1_ && nextticklistentry.time > this.worldInfo.getWorldTotalTime()) { break; } - - this.pendingTickListEntriesTreeSet.remove(nextticklistentry); - this.pendingTickListEntriesHashSet.remove(nextticklistentry); + blockUpdatesTracker.removeEntry(nextticklistentry, true); this.pendingTickListEntriesThisTick.add(nextticklistentry); } @@ -532,22 +687,22 @@ while (iterator.hasNext()) { - nextticklistentry = (NextTickListEntry)iterator.next(); + nextticklistentry = (kcauldron.BlockUpdateEntry)iterator.next(); iterator.remove(); //Keeping here as a note for future when it may be restored. //boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(nextticklistentry.xCoord >> 4, nextticklistentry.zCoord >> 4)); //byte b0 = isForced ? 0 : 8; byte b0 = 0; - if (this.checkChunksExist(nextticklistentry.xCoord - b0, nextticklistentry.yCoord - b0, nextticklistentry.zCoord - b0, nextticklistentry.xCoord + b0, nextticklistentry.yCoord + b0, nextticklistentry.zCoord + b0)) + if (this.checkChunksExist(nextticklistentry.x - b0, nextticklistentry.y - b0, nextticklistentry.z - b0, nextticklistentry.x + b0, nextticklistentry.y + b0, nextticklistentry.z + b0)) { - Block block = this.getBlock(nextticklistentry.xCoord, nextticklistentry.yCoord, nextticklistentry.zCoord); + Block block = this.getBlock(nextticklistentry.x, nextticklistentry.y, nextticklistentry.z); - if (block.getMaterial() != Material.air && Block.isEqualTo(block, nextticklistentry.func_151351_a())) + if (block.getMaterial() != Material.air && Block.isEqualTo(block, nextticklistentry.block)) { try { - block.updateTick(this, nextticklistentry.xCoord, nextticklistentry.yCoord, nextticklistentry.zCoord, this.rand); + block.updateTick(this, nextticklistentry.x, nextticklistentry.y, nextticklistentry.z, this.rand); } catch (Throwable throwable1) { @@ -557,27 +712,35 @@ try { - k = this.getBlockMetadata(nextticklistentry.xCoord, nextticklistentry.yCoord, nextticklistentry.zCoord); + k = this.getBlockMetadata(nextticklistentry.x, nextticklistentry.y, nextticklistentry.z); } catch (Throwable throwable) { k = -1; } - CrashReportCategory.func_147153_a(crashreportcategory, nextticklistentry.xCoord, nextticklistentry.yCoord, nextticklistentry.zCoord, block, k); - throw new ReportedException(crashreport); + CrashReportCategory.func_147153_a(crashreportcategory, nextticklistentry.x, nextticklistentry.y, nextticklistentry.z, block, k); + if (MinecraftServer.cauldronConfig.removeErroringBlocks.getValue()) + { + FMLLog.getLogger().log(org.apache.logging.log4j.Level.ERROR, crashreport.getCompleteReport()); + setBlockToAir(nextticklistentry.x, nextticklistentry.y, nextticklistentry.y); + } + else + { + throw new ReportedException(crashreport); + } } } } else { - this.scheduleBlockUpdate(nextticklistentry.xCoord, nextticklistentry.yCoord, nextticklistentry.zCoord, nextticklistentry.func_151351_a(), 0); + this.scheduleBlockUpdate(nextticklistentry.x, nextticklistentry.y, nextticklistentry.z, nextticklistentry.block, 0); } } this.theProfiler.endSection(); this.pendingTickListEntriesThisTick.clear(); - return !this.pendingTickListEntriesTreeSet.isEmpty(); + return !blockUpdatesTracker.isEmpty(); } } @@ -596,7 +759,7 @@ if (i1 == 0) { - iterator = this.pendingTickListEntriesTreeSet.iterator(); + iterator = this.blockUpdatesTracker.iterator(); } else { @@ -610,13 +773,13 @@ while (iterator.hasNext()) { - NextTickListEntry nextticklistentry = (NextTickListEntry)iterator.next(); + kcauldron.BlockUpdateEntry nextticklistentry = (kcauldron.BlockUpdateEntry)iterator.next(); - if (nextticklistentry.xCoord >= i && nextticklistentry.xCoord < j && nextticklistentry.zCoord >= k && nextticklistentry.zCoord < l) + if (nextticklistentry.x >= i && nextticklistentry.x < j && nextticklistentry.z >= k && nextticklistentry.z < l) { if (p_72920_2_) { - this.pendingTickListEntriesHashSet.remove(nextticklistentry); + //this.pendingTickListEntriesHashSet.remove(nextticklistentry); iterator.remove(); } @@ -651,7 +814,37 @@ protected IChunkProvider createChunkProvider() { IChunkLoader ichunkloader = this.saveHandler.getChunkLoader(this.provider); - this.theChunkProviderServer = new ChunkProviderServer(this, ichunkloader, this.provider.createChunkGenerator()); + // Cauldron start - if provider is vanilla, proceed to create a bukkit compatible chunk generator + if (this.provider.getClass().toString().length() <= 3 || this.provider.getClass().toString().contains("net.minecraft")) + { + // CraftBukkit start + org.bukkit.craftbukkit.generator.InternalChunkGenerator gen; + + if (this.generator != null) + { + gen = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, this.getSeed(), this.generator); + } + else if (this.provider instanceof WorldProviderHell) + { + gen = new org.bukkit.craftbukkit.generator.NetherChunkGenerator(this, this.getSeed()); + } + else if (this.provider instanceof WorldProviderEnd) + { + gen = new org.bukkit.craftbukkit.generator.SkyLandsChunkGenerator(this, this.getSeed()); + } + else + { + gen = new org.bukkit.craftbukkit.generator.NormalChunkGenerator(this, this.getSeed()); + } + this.theChunkProviderServer = new ChunkProviderServer(this, ichunkloader, gen); + // CraftBukkit end + } + else + // custom provider, load normally for forge compatibility + { + this.theChunkProviderServer = new ChunkProviderServer(this, ichunkloader, this.provider.createChunkGenerator()); + } + // Cauldron end return this.theChunkProviderServer; } @@ -659,29 +852,31 @@ { ArrayList arraylist = new ArrayList(); - for(int x = (p_147486_1_ >> 4); x <= (p_147486_4_ >> 4); x++) + // CraftBukkit start - Get tile entities from chunks instead of world + for (int chunkX = (p_147486_1_ >> 4); chunkX <= ((p_147486_4_ - 1) >> 4); chunkX++) { - for(int z = (p_147486_3_ >> 4); z <= (p_147486_6_ >> 4); z++) + for (int chunkZ = (p_147486_3_ >> 4); chunkZ <= ((p_147486_6_ - 1) >> 4); chunkZ++) { - Chunk chunk = getChunkFromChunkCoords(x, z); - if (chunk != null) + Chunk chunk = getChunkFromChunkCoords(chunkX, chunkZ); + + if (chunk == null) { - for(Object obj : chunk.chunkTileEntityMap.values()) + continue; + } + + for (Object te : chunk.chunkTileEntityMap.values()) + { + TileEntity tileentity = (TileEntity) te; + + if ((tileentity.xCoord >= p_147486_1_) && (tileentity.yCoord >= p_147486_2_) && (tileentity.zCoord >= p_147486_3_) + && (tileentity.xCoord < p_147486_4_) && (tileentity.yCoord < p_147486_5_) && (tileentity.zCoord < p_147486_6_)) { - TileEntity entity = (TileEntity)obj; - if (!entity.isInvalid()) - { - if (entity.xCoord >= p_147486_1_ && entity.yCoord >= p_147486_2_ && entity.zCoord >= p_147486_3_ && - entity.xCoord <= p_147486_4_ && entity.yCoord <= p_147486_5_ && entity.zCoord <= p_147486_6_) - { - arraylist.add(entity); - } - } + arraylist.add(tileentity); } } } } - + // CraftBukkit end return arraylist; } @@ -701,15 +896,17 @@ { this.entityIdMap = new IntHashMap(); } + + if (blockUpdatesTracker == null) blockUpdatesTracker = new kcauldron.BlockUpdatesTracker(this); if (this.pendingTickListEntriesHashSet == null) { - this.pendingTickListEntriesHashSet = new HashSet(); + this.pendingTickListEntriesHashSet = blockUpdatesTracker.hashSet; } if (this.pendingTickListEntriesTreeSet == null) { - this.pendingTickListEntriesTreeSet = new TreeSet(); + this.pendingTickListEntriesTreeSet = blockUpdatesTracker.treeSet; } this.createSpawnPosition(p_72963_1_); @@ -733,7 +930,28 @@ int i = 0; int j = this.provider.getAverageGroundLevel(); int k = 0; + // CraftBukkit start + if (this.generator != null) + { + Random rand = new Random(this.getSeed()); + org.bukkit.Location spawn = this.generator.getFixedSpawnLocation(((WorldServer) this).getWorld(), rand); + if (spawn != null) + { + if (spawn.getWorld() != ((WorldServer) this).getWorld()) + { + throw new IllegalStateException("Cannot set spawn point for " + this.worldInfo.getWorldName() + " to be in another world (" + + spawn.getWorld().getName() + ")"); + } + else + { + this.worldInfo.setSpawnPosition(spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ()); + this.findingSpawnPoint = false; + return; + } + } + } + // CraftBukkit end if (chunkposition != null) { i = chunkposition.chunkPosX; @@ -871,11 +1089,26 @@ public Entity getEntityByID(int p_73045_1_) { - return (Entity)this.entityIdMap.lookup(p_73045_1_); + Entity entity = (Entity)this.entityIdMap.lookup(p_73045_1_); + return entity == null || entity.isDead ? null : entity; } public boolean addWeatherEffect(Entity p_72942_1_) { + // Cauldron start - vanilla compatibility + if (p_72942_1_ instanceof net.minecraft.entity.effect.EntityLightningBolt) + { + // CraftBukkit start + LightningStrikeEvent lightning = new LightningStrikeEvent(this.getWorld(), (org.bukkit.entity.LightningStrike) p_72942_1_.getBukkitEntity()); + this.getServer().getPluginManager().callEvent(lightning); + + if (lightning.isCancelled()) + { + return false; + } + // CraftBukkit end + } + // Cauldron end if (super.addWeatherEffect(p_72942_1_)) { this.mcServer.getConfigurationManager().sendToAllNear(p_72942_1_.posX, p_72942_1_.posY, p_72942_1_.posZ, 512.0D, this.provider.dimensionId, new S2CPacketSpawnGlobalEntity(p_72942_1_)); @@ -894,13 +1127,23 @@ public Explosion newExplosion(Entity p_72885_1_, double p_72885_2_, double p_72885_4_, double p_72885_6_, float p_72885_8_, boolean p_72885_9_, boolean p_72885_10_) { + // CraftBukkit start + Explosion explosion = super.newExplosion(p_72885_1_, p_72885_2_, p_72885_4_, p_72885_6_, p_72885_8_, p_72885_9_, p_72885_10_); + + if (explosion.wasCanceled) + { + return explosion; + } + + /* Remove Explosion explosion = new Explosion(this, p_72885_1_, p_72885_2_, p_72885_4_, p_72885_6_, p_72885_8_); explosion.isFlaming = p_72885_9_; explosion.isSmoking = p_72885_10_; if (net.minecraftforge.event.ForgeEventFactory.onExplosionStart(this, explosion)) return explosion; explosion.doExplosionA(); explosion.doExplosionB(false); - + */ + // CraftBukkit end - TODO: Check if explosions are still properly implemented if (!p_72885_10_) { explosion.affectedBlockPositions.clear(); @@ -977,7 +1220,7 @@ { boolean flag = this.isRaining(); super.updateWeather(); - + /* CraftBukkit start if (this.prevRainingStrength != this.rainingStrength) { this.mcServer.getConfigurationManager().sendPacketToAllPlayersInDimension(new S2BPacketChangeGameState(7, this.rainingStrength), this.provider.dimensionId); @@ -988,10 +1231,6 @@ this.mcServer.getConfigurationManager().sendPacketToAllPlayersInDimension(new S2BPacketChangeGameState(8, this.thunderingStrength), this.provider.dimensionId); } - /*The function in use here has been replaced in order to only send the weather info to players in the correct dimension, - rather than to all players on the server. This is what causes the client-side rain, as the - client believes that it has started raining locally, rather than in another dimension. - */ if (flag != this.isRaining()) { if (flag) @@ -1006,6 +1245,33 @@ this.mcServer.getConfigurationManager().sendPacketToAllPlayersInDimension(new S2BPacketChangeGameState(7, this.rainingStrength), this.provider.dimensionId); this.mcServer.getConfigurationManager().sendPacketToAllPlayersInDimension(new S2BPacketChangeGameState(8, this.thunderingStrength), this.provider.dimensionId); } + // */ + if (flag != this.isRaining()) + { + if (flag) + { + this.mcServer.getConfigurationManager().sendPacketToAllPlayersInDimension(new S2BPacketChangeGameState(2, 0.0F), super.provider.dimensionId); + } + else + { + this.mcServer.getConfigurationManager().sendPacketToAllPlayersInDimension(new S2BPacketChangeGameState(1, 0.0F), super.provider.dimensionId); + } + + this.mcServer.getConfigurationManager().sendPacketToAllPlayersInDimension(new S2BPacketChangeGameState(7, super.rainingStrength), + super.provider.dimensionId); + this.mcServer.getConfigurationManager().sendPacketToAllPlayersInDimension(new S2BPacketChangeGameState(8, super.thunderingStrength), + super.provider.dimensionId); + + // Only send weather packets to those affected + for (int i = 0; i < this.playerEntities.size(); ++i) + { + if (((EntityPlayerMP) this.playerEntities.get(i)).worldObj == this) + { + ((EntityPlayerMP) this.playerEntities.get(i)).setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false); + } + } + // CraftBukkit end + } } protected int func_152379_p() @@ -1069,4 +1335,54 @@ this(); } } + + // CraftBukkit start - Compatibility methods for BlockChangeDelegate + public boolean setRawTypeId(int x, int y, int z, int typeId) + { + return this.setBlock(x, y, z, Block.getBlockById(typeId), 0, 4); + } + + public boolean setRawTypeIdAndData(int x, int y, int z, int typeId, int data) + { + return this.setBlock(x, y, z, Block.getBlockById(typeId), data, 4); + } + + public boolean setTypeId(int x, int y, int z, int typeId) + { + return this.setBlock(x, y, z, Block.getBlockById(typeId), 0, 3); + } + + public boolean setTypeIdAndData(int x, int y, int z, int typeId, int data) + { + return this.setBlock(x, y, z, Block.getBlockById(typeId), data, 3); + } + + public int getTypeId(int x, int y, int z) + { + return Block.getIdFromBlock(getBlock(x, y, z)); + } + + public boolean setTypeAndData(int x, int y, int z, Block block, int data, int flag) + { + return this.setBlock(x, y, z, block, data, flag); + } + + public boolean setData(int x, int y, int z, int data, int flag) + { + return this.setBlockMetadataWithNotify(x, y, z, data, flag); + } + + public int getData(int x, int y, int z) + { + return this.getBlockMetadata(x, y, z); + } + + public Block getType(int x, int y, int z) + { + return this.getBlock(x, y, z); + } + // CraftBukkit end + + // KCauldron start + public kcauldron.BlockUpdatesTracker blockUpdatesTracker; }