Files
2025-02-04 06:57:42 +08:00

859 lines
42 KiB
Diff

--- ../src-base/minecraft/net/minecraft/world/WorldServer.java
+++ ../src-work/minecraft/net/minecraft/world/WorldServer.java
@@ -14,27 +14,25 @@
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
-import java.util.function.Predicate;
+import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import net.minecraft.advancements.AdvancementManager;
import net.minecraft.advancements.FunctionManager;
import net.minecraft.block.Block;
import net.minecraft.block.BlockEventData;
+import net.minecraft.block.BlockJukebox;
+import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.entity.Entity;
-import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.EntityTracker;
import net.minecraft.entity.EnumCreatureType;
-import net.minecraft.entity.INpc;
import net.minecraft.entity.effect.EntityLightningBolt;
-import net.minecraft.entity.passive.EntityAnimal;
import net.minecraft.entity.passive.EntitySkeletonHorse;
-import net.minecraft.entity.passive.EntityWaterMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
@@ -50,6 +48,7 @@
import net.minecraft.scoreboard.ServerScoreboard;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.PlayerChunkMap;
+import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.IProgressUpdate;
import net.minecraft.util.IThreadListener;
@@ -77,16 +76,19 @@
import net.minecraft.world.storage.WorldInfo;
import net.minecraft.world.storage.WorldSavedDataCallableSave;
import net.minecraft.world.storage.loot.LootTableManager;
+import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.event.weather.LightningStrikeEvent;
public class WorldServer extends World implements IThreadListener
{
private static final Logger LOGGER = LogManager.getLogger();
private final MinecraftServer mcServer;
- private final EntityTracker entityTracker;
+ public EntityTracker entityTracker;
private final PlayerChunkMap playerChunkMap;
private final Set<NextTickListEntry> pendingTickListEntriesHashSet = Sets.<NextTickListEntry>newHashSet();
private final TreeSet<NextTickListEntry> pendingTickListEntriesTreeSet = new TreeSet<NextTickListEntry>();
@@ -97,34 +99,92 @@
private final Teleporter worldTeleporter;
private final WorldEntitySpawner entitySpawner = new WorldEntitySpawner();
protected final VillageSiege villageSiege = new VillageSiege(this);
- private final WorldServer.ServerBlockEventList[] blockEventQueue = new WorldServer.ServerBlockEventList[] {new WorldServer.ServerBlockEventList(), new WorldServer.ServerBlockEventList()};
+ private final ServerBlockEventList[] blockEventQueue = new ServerBlockEventList[] {new ServerBlockEventList(), new ServerBlockEventList()};
private int blockEventCacheIndex;
private final List<NextTickListEntry> pendingTickListEntriesThisTick = Lists.<NextTickListEntry>newArrayList();
+ /** Stores the recently processed (lighting) chunks */
+ protected Set<ChunkPos> doneChunks = new java.util.HashSet<ChunkPos>();
+ public List<Teleporter> customTeleporters = new ArrayList<Teleporter>();
+
+ public final int dimension;
+
+ private int lastTick = 0; // CatServer - implement realtime
+
+ public WorldServer(MinecraftServer server, ISaveHandler saveHandlerIn, WorldInfo info, int dimensionId, Profiler methodprofiler, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) {
+ super(saveHandlerIn, info, net.minecraftforge.common.DimensionManager.createProviderFor(dimensionId), methodprofiler, false, gen, env);
+ this.pvpMode = server.isPVPEnabled();
+ info.world = this;
+ this.dimension = dimensionId;
+ this.mcServer = server;
+ this.entityTracker = new EntityTracker(this);
+ this.playerChunkMap = new PlayerChunkMap(this);
+ // Guarantee the dimension ID was not reset by the provider
+ int providerDim = this.provider.getDimension();
+ this.provider.setWorld(this);
+ this.provider.setDimension(providerDim);
+ this.chunkProvider = this.createChunkProvider();
+ this.worldTeleporter = new org.bukkit.craftbukkit.CraftTravelAgent(this); // CraftBukkit
+ this.calculateInitialSkylight();
+ this.calculateInitialWeather();
+ this.getWorldBorder().setSize(server.getMaxWorldSize());
+ // CatServer start - if overworld has loaded, use its mapstorage
+ WorldServer overworld = DimensionManager.getWorld(0);
+ if (overworld != null)
+ {
+ this.mapStorage = overworld.mapStorage;
+ perWorldStorage = new MapStorage(new net.minecraftforge.common.WorldSpecificSaveHandler(this, overworld.saveHandler));
+ }
+ else
+ {
+ this.mapStorage = new MapStorage(saveHandlerIn);
+ perWorldStorage = new MapStorage(new net.minecraftforge.common.WorldSpecificSaveHandler(this, saveHandler));
+ }
+ // CatServer end
+ net.minecraftforge.common.DimensionManager.setWorld(dimensionId, this, mcServer);
+ }
+
public WorldServer(MinecraftServer server, ISaveHandler saveHandlerIn, WorldInfo info, int dimensionId, Profiler profilerIn)
{
- super(saveHandlerIn, info, DimensionType.getById(dimensionId).createDimension(), profilerIn, false);
+ super(saveHandlerIn, info, net.minecraftforge.common.DimensionManager.createProviderFor(dimensionId), profilerIn, false);
this.mcServer = server;
this.entityTracker = new EntityTracker(this);
this.playerChunkMap = new PlayerChunkMap(this);
+ this.dimension = dimensionId;
+ // Guarantee the dimension ID was not reset by the provider
+ int providerDim = this.provider.getDimension();
this.provider.setWorld(this);
+ this.provider.setDimension(providerDim);
this.chunkProvider = this.createChunkProvider();
this.worldTeleporter = new Teleporter(this);
this.calculateInitialSkylight();
this.calculateInitialWeather();
this.getWorldBorder().setSize(server.getMaxWorldSize());
+ // CatServer start - if overworld has loaded, use its mapstorage
+ WorldServer overworld = DimensionManager.getWorld(0);
+ if (overworld != null)
+ {
+ this.mapStorage = overworld.mapStorage;
+ perWorldStorage = new MapStorage(new net.minecraftforge.common.WorldSpecificSaveHandler(this, overworld.saveHandler));
+ }
+ else
+ {
+ this.mapStorage = new MapStorage(saveHandlerIn);
+ perWorldStorage = new MapStorage(new net.minecraftforge.common.WorldSpecificSaveHandler(this, saveHandler));
+ }
+ // CatServer end
+ net.minecraftforge.common.DimensionManager.setWorld(dimensionId, this, mcServer);
}
public World init()
{
- this.mapStorage = new MapStorage(this.saveHandler);
String s = VillageCollection.fileNameForProvider(this.provider);
- VillageCollection villagecollection = (VillageCollection)this.mapStorage.getOrLoadData(VillageCollection.class, s);
+ VillageCollection villagecollection = (VillageCollection)this.perWorldStorage.getOrLoadData(VillageCollection.class, s);
if (villagecollection == null)
{
this.villageCollection = new VillageCollection(this);
- this.mapStorage.setData(s, this.villageCollection);
+ this.perWorldStorage.setData(s, this.villageCollection);
}
else
{
@@ -132,19 +192,31 @@
this.villageCollection.setWorldsForAll(this);
}
- this.worldScoreboard = new ServerScoreboard(this.mcServer);
- ScoreboardSaveData scoreboardsavedata = (ScoreboardSaveData)this.mapStorage.getOrLoadData(ScoreboardSaveData.class, "scoreboard");
+ if (getServer().getScoreboardManager() == null) { // CraftBukkit
+ this.worldScoreboard = new ServerScoreboard(this.mcServer);
+ ScoreboardSaveData scoreboardsavedata = (ScoreboardSaveData)this.mapStorage.getOrLoadData(ScoreboardSaveData.class, "scoreboard");
+
+ if (scoreboardsavedata == null)
+ {
+ scoreboardsavedata = new ScoreboardSaveData();
+ this.mapStorage.setData("scoreboard", scoreboardsavedata);
+ }
- if (scoreboardsavedata == null)
- {
- scoreboardsavedata = new ScoreboardSaveData();
- this.mapStorage.setData("scoreboard", scoreboardsavedata);
+ scoreboardsavedata.setScoreboard(this.worldScoreboard);
+ ((ServerScoreboard)this.worldScoreboard).addDirtyRunnable(new WorldSavedDataCallableSave(scoreboardsavedata));
+ } else {
+ this.worldScoreboard = getServer().getScoreboardManager().getMainScoreboard().getHandle();
}
- scoreboardsavedata.setScoreboard(this.worldScoreboard);
- ((ServerScoreboard)this.worldScoreboard).addDirtyRunnable(new WorldSavedDataCallableSave(scoreboardsavedata));
this.lootTable = new LootTableManager(new File(new File(this.saveHandler.getWorldDirectory(), "data"), "loot_tables"));
- this.advancementManager = new AdvancementManager(new File(new File(this.saveHandler.getWorldDirectory(), "data"), "advancements"));
+ // CraftBukkit start
+ if (this.dimension != 0) { // SPIGOT-3899 multiple worlds of advancements not supported
+ this.advancementManager = this.mcServer.getAdvancementManager();
+ }
+ if (this.advancementManager == null) {
+ this.advancementManager = new AdvancementManager(new File(new File(this.saveHandler.getWorldDirectory(), "data"), "advancements"));
+ }
+ // CraftBukkit end
this.functionManager = new FunctionManager(new File(new File(this.saveHandler.getWorldDirectory(), "data"), "functions"), this.mcServer);
this.getWorldBorder().setCenter(this.worldInfo.getBorderCenterX(), this.worldInfo.getBorderCenterZ());
this.getWorldBorder().setDamageAmount(this.worldInfo.getBorderDamagePerBlock());
@@ -161,13 +233,46 @@
this.getWorldBorder().setTransition(this.worldInfo.getBorderSize());
}
+ this.initCapabilities();
return this;
}
+ @Override
+ public TileEntity getTileEntity(BlockPos pos) {
+ return super.getTileEntity(pos); // CatServer - not fix te
+ }
+
+ private TileEntity fixTileEntity(BlockPos pos, Block type, TileEntity found) {
+ this.getServer().getLogger().log(Level.SEVERE, "Block at {0},{1},{2} is {3} but has {4}" + ". "
+ + "Bukkit will attempt to fix this, but there may be additional damage that we cannot recover.", new Object[]{pos.getX(), pos.getY(), pos.getZ(), org.bukkit.Material.getBlockMaterial(Block.getIdFromBlock(type)).toString(), found});
+ if (type instanceof ITileEntityProvider) {
+ TileEntity replacement = ((ITileEntityProvider) type).createNewTileEntity(this, type.getMetaFromState(this.getBlockState(pos)));
+ replacement.world = this;
+ this.setTileEntity(pos, replacement);
+ return replacement;
+ } else {
+ this.getServer().getLogger().severe("Don't know how to fix for this type... Can't do anything! :(");
+ return found;
+ }
+ }
+
+ 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);
+ }
+ }
+
public void tick()
{
super.tick();
+ // CatServer start - implement realtime
+ int elapsedTicks = this.lastTick > 0 ? catserver.server.CatServer.getCurrentTick() - this.lastTick : 1;
+ this.lastTick = catserver.server.CatServer.getCurrentTick();
+ // CatServer end
+
if (this.getWorldInfo().isHardcoreModeEnabled() && this.getDifficulty() != EnumDifficulty.HARD)
{
this.getWorldInfo().setDifficulty(EnumDifficulty.HARD);
@@ -179,8 +284,8 @@
{
if (this.getGameRules().getBoolean("doDaylightCycle"))
{
- long i = this.worldInfo.getWorldTime() + 24000L;
- this.worldInfo.setWorldTime(i - i % 24000L);
+ long i = this.getWorldTime() + 24000L;
+ this.setWorldTime(i - i % 24000L);
}
this.wakeAllPlayers();
@@ -188,11 +293,17 @@
this.profiler.startSection("mobSpawner");
- if (this.getGameRules().getBoolean("doMobSpawning") && this.worldInfo.getTerrainType() != WorldType.DEBUG_ALL_BLOCK_STATES)
+ // 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().getBoolean("doMobSpawning") && this.worldInfo.getTerrainType() != WorldType.DEBUG_ALL_BLOCK_STATES && (this.spawnHostileMobs || this.spawnPeacefulMobs) && this.playerEntities.size() > 0)
{
- this.entitySpawner.findChunksForSpawning(this, this.spawnHostileMobs, this.spawnPeacefulMobs, this.worldInfo.getWorldTotalTime() % 400L == 0L);
+ timings.mobSpawn.startTiming(); // Spigot
+ this.entitySpawner.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.profiler.endStartSection("chunkSource");
this.chunkProvider.tick();
int j = this.calculateSkylightSubtracted(1.0F);
@@ -206,34 +317,58 @@
if (this.getGameRules().getBoolean("doDaylightCycle"))
{
- this.worldInfo.setWorldTime(this.worldInfo.getWorldTime() + 1L);
+ if (catserver.server.CatServer.getConfig().enableRealtime) this.setWorldTime(this.getWorldTime() + elapsedTicks); else // CatServer - implement realtime
+ this.setWorldTime(this.getWorldTime() + 1L);
}
+ timings.doChunkUnload.stopTiming(); // Spigot
this.profiler.endStartSection("tickPending");
+ timings.doTickPending.startTiming(); // Spigot
this.tickUpdates(false);
+ timings.doTickPending.stopTiming(); // Spigot
this.profiler.endStartSection("tickBlocks");
+ timings.doTickTiles.startTiming(); // Spigot
this.updateBlocks();
+ timings.doTickTiles.stopTiming(); // Spigot
this.profiler.endStartSection("chunkMap");
+ timings.doChunkMap.startTiming(); // Spigot
this.playerChunkMap.tick();
+ timings.doChunkMap.stopTiming(); // Spigot
this.profiler.endStartSection("village");
+ timings.doVillages.startTiming(); // Spigot
this.villageCollection.tick();
this.villageSiege.tick();
+ timings.doVillages.stopTiming(); // Spigot
this.profiler.endStartSection("portalForcer");
+ timings.doPortalForcer.startTiming(); // Spigot
this.worldTeleporter.removeStalePortalLocations(this.getTotalWorldTime());
+ for (Teleporter tele : customTeleporters)
+ {
+ tele.removeStalePortalLocations(getTotalWorldTime());
+ }
+ timings.doPortalForcer.stopTiming(); // Spigot
this.profiler.endSection();
+ timings.doSounds.startTiming(); // Spigot
this.sendQueuedBlockEvents();
+ timings.doSounds.stopTiming(); // Spigot
+
+ timings.doChunkGC.startTiming();// Spigot
+ this.getWorld().processChunkGC();
+ timings.doChunkGC.stopTiming(); // Spigot
}
@Nullable
public Biome.SpawnListEntry getSpawnListEntryForTypeAt(EnumCreatureType creatureType, BlockPos pos)
{
List<Biome.SpawnListEntry> list = this.getChunkProvider().getPossibleCreatures(creatureType, pos);
+ list = net.minecraftforge.event.ForgeEventFactory.getPotentialSpawns(this, creatureType, pos, list);
return list != null && !list.isEmpty() ? (Biome.SpawnListEntry)WeightedRandom.getRandomItem(this.rand, list) : null;
}
public boolean canCreatureTypeSpawnHere(EnumCreatureType creatureType, Biome.SpawnListEntry spawnListEntry, BlockPos pos)
{
List<Biome.SpawnListEntry> list = this.getChunkProvider().getPossibleCreatures(creatureType, pos);
+ list = net.minecraftforge.event.ForgeEventFactory.getPotentialSpawns(this, creatureType, pos, list);
return list != null && !list.isEmpty() ? list.contains(spawnListEntry) : false;
}
@@ -252,7 +387,7 @@
{
++i;
}
- else if (entityplayer.isPlayerSleeping())
+ else if (entityplayer.isPlayerSleeping() || entityplayer.fauxSleeping)
{
++j;
}
@@ -279,25 +414,29 @@
private void resetRainAndThunder()
{
- this.worldInfo.setRainTime(0);
- this.worldInfo.setRaining(false);
- this.worldInfo.setThunderTime(0);
- this.worldInfo.setThundering(false);
+ this.provider.resetRainAndThunder();
}
+ // TODO: Test this method
public boolean areAllPlayersAsleep()
{
if (this.allPlayersSleeping && !this.isRemote)
{
+ // 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;
+
for (EntityPlayer entityplayer : this.playerEntities)
{
- if (!entityplayer.isSpectator() && !entityplayer.isPlayerFullyAsleep())
+ if (entityplayer.isPlayerFullyAsleep()) {
+ foundActualSleepers = true;
+ }
+ if (!entityplayer.isSpectator() && !entityplayer.isPlayerFullyAsleep() || entityplayer.fauxSleeping)
{
return false;
}
}
- return true;
+ return foundActualSleepers;
}
else
{
@@ -333,7 +472,7 @@
this.worldInfo.setSpawnZ(j);
}
- protected boolean isChunkLoaded(int x, int z, boolean allowEmpty)
+ public boolean isChunkLoaded(int x, int z, boolean allowEmpty)
{
return this.getChunkProvider().chunkExists(x, z);
}
@@ -342,7 +481,7 @@
{
this.profiler.startSection("playerCheckLight");
- if (!this.playerEntities.isEmpty())
+ if (spigotConfig.randomLightUpdates && !this.playerEntities.isEmpty()) // Spigot
{
int i = this.rand.nextInt(this.playerEntities.size());
EntityPlayer entityplayer = this.playerEntities.get(i);
@@ -375,7 +514,7 @@
boolean flag1 = this.isThundering();
this.profiler.startSection("pollingChunks");
- for (Iterator<Chunk> iterator = this.playerChunkMap.getChunkIterator(); iterator.hasNext(); this.profiler.endSection())
+ for (Iterator<Chunk> iterator = getPersistentChunkIterable(this.playerChunkMap.getChunkIterator()); iterator.hasNext(); this.profiler.endSection())
{
this.profiler.startSection("getChunk");
Chunk chunk = iterator.next();
@@ -385,9 +524,10 @@
chunk.enqueueRelightChecks();
this.profiler.endStartSection("tickChunk");
chunk.onTick(false);
+ if (!chunk.areNeighborsLoaded(1)) continue; // Spigot
this.profiler.endStartSection("thunder");
- if (flag && flag1 && this.rand.nextInt(100000) == 0)
+ if (this.provider.canDoLightning(chunk) && flag && flag1 && this.rand.nextInt(100000) == 0)
{
this.updateLCG = this.updateLCG * 3 + 1013904223;
int l = this.updateLCG >> 2;
@@ -403,7 +543,7 @@
entityskeletonhorse.setTrap(true);
entityskeletonhorse.setGrowingAge(0);
entityskeletonhorse.setPosition((double)blockpos.getX(), (double)blockpos.getY(), (double)blockpos.getZ());
- this.spawnEntity(entityskeletonhorse);
+ this.addEntity(entityskeletonhorse, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING);
this.addWeatherEffect(new EntityLightningBolt(this, (double)blockpos.getX(), (double)blockpos.getY(), (double)blockpos.getZ(), true));
}
else
@@ -415,21 +555,24 @@
this.profiler.endStartSection("iceandsnow");
- if (this.rand.nextInt(16) == 0)
+ if (this.provider.canDoRainSnowIce(chunk) && this.rand.nextInt(16) == 0)
{
this.updateLCG = this.updateLCG * 3 + 1013904223;
int j2 = this.updateLCG >> 2;
BlockPos blockpos1 = this.getPrecipitationHeight(new BlockPos(j + (j2 & 15), 0, k + (j2 >> 8 & 15)));
BlockPos blockpos2 = blockpos1.down();
+ if (this.isAreaLoaded(blockpos2, 1)) // Forge: check area to avoid loading neighbors in unloaded chunks
if (this.canBlockFreezeNoWater(blockpos2))
{
- this.setBlockState(blockpos2, Blocks.ICE.getDefaultState());
+ // this.setBlockState(blockpos2, Blocks.ICE.getDefaultState());
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockpos2, Blocks.ICE.getDefaultState(), null);
}
if (flag && this.canSnowAt(blockpos1, true))
{
- this.setBlockState(blockpos1, Blocks.SNOW_LAYER.getDefaultState());
+ // this.setBlockState(blockpos1, Blocks.SNOW_LAYER.getDefaultState());
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockpos1, Blocks.SNOW_LAYER.getDefaultState(), null);
}
if (flag && this.getBiome(blockpos2).canRain())
@@ -525,7 +668,10 @@
{
if (blockIn.requiresUpdates())
{
- if (this.isAreaLoaded(pos.add(-8, -8, -8), pos.add(8, 8, 8)))
+ //Keeping here as a note for future when it may be restored.
+ boolean isForced = getPersistentChunks().containsKey(new ChunkPos(pos));
+ int range = isForced ? 0 : 8;
+ if (this.isAreaLoaded(pos.add(-range, -range, -range), pos.add(range, range, range)))
{
IBlockState iblockstate = this.getBlockState(pos);
@@ -561,6 +707,7 @@
public void scheduleBlockUpdate(BlockPos pos, Block blockIn, int delay, int priority)
{
+ if (blockIn == null) return; //Forge: Prevent null blocks from ticking, can happen if blocks are removed in old worlds. TODO: Fix real issue causing block to be null.
NextTickListEntry nextticklistentry = new NextTickListEntry(pos, blockIn);
nextticklistentry.setPriority(priority);
Material material = blockIn.getDefaultState().getMaterial();
@@ -579,9 +726,9 @@
public void updateEntities()
{
- if (this.playerEntities.isEmpty())
+ if (this.playerEntities.isEmpty() && getPersistentChunks().isEmpty()) // CatServer - Use Forge logic here
{
- if (this.updateEntityTick++ >= 300)
+ if (this.updateEntityTick++ >= 300 && MinecraftServer.currentTick % 20 > 0) // CatServer - Prevent entity cleanup, other issues on servers with no players
{
return;
}
@@ -593,6 +740,8 @@
this.provider.onWorldUpdateEntities();
super.updateEntities();
+ catserver.server.WorldTickSkipManager.update(this); // CatServer
+ spigotConfig.currentPrimedTnt = 0; // Spigot
}
protected void tickPlayers()
@@ -668,6 +817,7 @@
{
int i = this.pendingTickListEntriesTreeSet.size();
+ // TODO: Check if this condition should be always false(HashTreeSet from CB related)
if (i != this.pendingTickListEntriesHashSet.size())
{
throw new IllegalStateException("TickNextTick list out of synch");
@@ -676,7 +826,14 @@
{
if (i > 65536)
{
- i = 65536;
+ // i = 65536;
+ // CraftBukkit start - If the server has too much to process over time, try to alleviate that
+ if (i > 20 * 65536) {
+ i = i / 20;
+ } else {
+ i = 65536;
+ }
+ // CraftBukkit end
}
this.profiler.startSection("cleaning");
@@ -703,6 +860,9 @@
{
NextTickListEntry nextticklistentry1 = iterator.next();
iterator.remove();
+ //Keeping here as a note for future when it may be restored.
+ //boolean isForced = getPersistentChunks().containsKey(new ChunkPos(nextticklistentry.xCoord >> 4, nextticklistentry.zCoord >> 4));
+ //byte b0 = isForced ? 0 : 8;
int k = 0;
if (this.isAreaLoaded(nextticklistentry1.position.add(0, 0, 0), nextticklistentry1.position.add(0, 0, 0)))
@@ -796,6 +956,7 @@
return list;
}
+ /* CraftBukkit start - We prevent spawning in general, so this butchering is not needed
public void updateEntityWithOptionalForce(Entity entityIn, boolean forceUpdate)
{
if (!this.canSpawnAnimals() && (entityIn instanceof EntityAnimal || entityIn instanceof EntityWaterMob))
@@ -810,6 +971,7 @@
super.updateEntityWithOptionalForce(entityIn, forceUpdate);
}
+ // CraftBukkit end */
private boolean canSpawnNPCs()
{
@@ -824,11 +986,68 @@
protected IChunkProvider createChunkProvider()
{
IChunkLoader ichunkloader = this.saveHandler.getChunkLoader(this.provider);
- return new ChunkProviderServer(this, ichunkloader, this.provider.createChunkGenerator());
+ // CatServer - 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.chunkProvider = new ChunkProviderServer(this, ichunkloader, gen);
+ // CraftBukkit end
+ } else { // custom provider, load normally for forge compatibility
+ this.chunkProvider = new ChunkProviderServer(this, ichunkloader, this.provider.createChunkGenerator());
+ }
+ return chunkProvider;
}
+ public List<TileEntity> getTileEntities(int i, int j, int k, int l, int i1, int j1) {
+ ArrayList arraylist = Lists.newArrayList();
+
+ // CraftBukkit start - Get tile entities from chunks instead of world
+ for (int chunkX = (i >> 4); chunkX <= ((l - 1) >> 4); chunkX++) {
+ for (int chunkZ = (k >> 4); chunkZ <= ((j1 - 1) >> 4); chunkZ++) {
+ Chunk chunk = getChunkFromChunkCoords(chunkX, chunkZ);
+ if (chunk == null) {
+ continue;
+ }
+ for (Object te : chunk.getTileEntityMap().values()) {
+ TileEntity tileentity = (TileEntity) te;
+ if ((tileentity.getPos().getX() >= i) && (tileentity.getPos().getY() >= j) && (tileentity.getPos().getZ() >= k) && (tileentity.getPos().getX() < l) && (tileentity.getPos().getY() < i1) && (tileentity.getPos().getZ() < j1)) {
+ arraylist.add(tileentity);
+ }
+ }
+ }
+ }
+ /*
+ for (int k1 = 0; k1 < this.tileEntityList.size(); ++k1) {
+ TileEntity tileentity = (TileEntity) this.tileEntityList.get(k1);
+ BlockPosition blockposition = tileentity.getPosition();
+
+ if (blockposition.getX() >= i && blockposition.getY() >= j && blockposition.getZ() >= k && blockposition.getX() < l && blockposition.getY() < i1 && blockposition.getZ() < j1) {
+ arraylist.add(tileentity);
+ }
+ }
+ */
+ // CraftBukkit end
+
+ return arraylist;
+ }
+
public boolean isBlockModifiable(EntityPlayer player, BlockPos pos)
{
+ return super.isBlockModifiable(player, pos);
+ }
+ public boolean canMineBlockBody(EntityPlayer player, BlockPos pos)
+ {
return !this.mcServer.isBlockProtected(this, pos, player) && this.getWorldBorder().contains(pos);
}
@@ -894,6 +1113,7 @@
}
else
{
+ if (net.minecraftforge.event.ForgeEventFactory.onCreateWorldSpawn(this, settings)) return;
this.findingSpawnPoint = true;
BiomeProvider biomeprovider = this.provider.getBiomeProvider();
List<Biome> list = biomeprovider.getBiomesToSpawnIn();
@@ -903,6 +1123,23 @@
int j = this.provider.getAverageGroundLevel();
int k = 8;
+ // 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.setSpawn(new BlockPos(spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ()));
+ this.findingSpawnPoint = false;
+ return;
+ }
+ }
+ }
+ // CraftBukkit end
+
if (blockpos != null)
{
i = blockpos.getX();
@@ -915,7 +1152,7 @@
int l = 0;
- while (!this.provider.canCoordinateBeSpawn(i, k))
+ while (!this.canSpawn(i, k)) // CraftBukkit - use our own canSpawn
{
i += random.nextInt(64) - random.nextInt(64);
k += random.nextInt(64) - random.nextInt(64);
@@ -966,6 +1203,7 @@
if (chunkproviderserver.canSave())
{
+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld()));
if (progressCallback != null)
{
progressCallback.displaySavingString("Saving level");
@@ -979,6 +1217,7 @@
}
chunkproviderserver.saveChunks(all);
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.WorldEvent.Save(this));
for (Chunk chunk : Lists.newArrayList(chunkproviderserver.getLoadedChunks()))
{
@@ -1012,6 +1251,12 @@
}
}
+ // CraftBukkit start - Save secondary data for nether/end
+ if (this instanceof WorldServerMulti) {
+ ((WorldServerMulti) this).saveAdditionalData();
+ }
+ // CraftBukkit end
+
this.worldInfo.setBorderSize(this.getWorldBorder().getDiameter());
this.worldInfo.getBorderCenterX(this.getWorldBorder().getCenterX());
this.worldInfo.getBorderCenterZ(this.getWorldBorder().getCenterZ());
@@ -1023,18 +1268,27 @@
this.worldInfo.setBorderLerpTime(this.getWorldBorder().getTimeUntilTarget());
this.saveHandler.saveWorldInfoWithPlayer(this.worldInfo, this.mcServer.getPlayerList().getHostPlayerData());
this.mapStorage.saveAllData();
+ this.perWorldStorage.saveAllData();
}
+ // CatServer start - Redirect method for mod mixin compatibility
public boolean spawnEntity(Entity entityIn)
{
- return this.canAddEntity(entityIn) ? super.spawnEntity(entityIn) : false;
+ return this.addEntity(entityIn, CreatureSpawnEvent.SpawnReason.DEFAULT);
}
+ // CatServer end
+ public boolean addEntity(Entity entityIn, CreatureSpawnEvent.SpawnReason spawnReason) {
+ // World.spawnEntity(Entity) will call this, and we still want to perform
+ // existing entity checking when it's called with a SpawnReason
+ return this.canAddEntity(entityIn) ? super.addEntity(entityIn, spawnReason) : false;
+ }
+
public void loadEntities(Collection<Entity> entityCollection)
{
for (Entity entity : Lists.newArrayList(entityCollection))
{
- if (this.canAddEntity(entity))
+ if (this.canAddEntity(entity) && !net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityJoinWorldEvent(entity, this)))
{
this.loadedEntityList.add(entity);
this.onEntityAdded(entity);
@@ -1046,7 +1300,7 @@
{
if (entityIn.isDead)
{
- LOGGER.warn("Tried to add entity {} but it was marked as removed already", (Object)EntityList.getKey(entityIn));
+ // LOGGER.warn("Tried to add entity {} but it was marked as removed already", (Object)EntityList.getKey(entityIn));
return false;
}
else
@@ -1065,7 +1319,7 @@
{
if (!(entityIn instanceof EntityPlayer))
{
- LOGGER.warn("Keeping entity {} that already exists with UUID {}", EntityList.getKey(entity), uuid.toString());
+ // LOGGER.warn("Keeping entity {} that already exists with UUID {}", EntityList.getKey(entity), uuid.toString());
return false;
}
@@ -1113,9 +1367,18 @@
public boolean addWeatherEffect(Entity entityIn)
{
+ // CatServer - ignore modded weather effect
+ if (entityIn.getBukkitEntity() instanceof org.bukkit.entity.LightningStrike) {
+ LightningStrikeEvent lightning = new LightningStrikeEvent(this.getWorld(), (org.bukkit.entity.LightningStrike) entityIn.getBukkitEntity());
+ this.getServer().getPluginManager().callEvent(lightning);
+
+ if (lightning.isCancelled()) {
+ return false;
+ }
+ }
if (super.addWeatherEffect(entityIn))
{
- this.mcServer.getPlayerList().sendToAllNearExcept((EntityPlayer)null, entityIn.posX, entityIn.posY, entityIn.posZ, 512.0D, this.provider.getDimensionType().getId(), new SPacketSpawnGlobalEntity(entityIn));
+ this.mcServer.getPlayerList().sendToAllNearExcept((EntityPlayer)null, entityIn.posX, entityIn.posY, entityIn.posZ, 512.0D, dimension, new SPacketSpawnGlobalEntity(entityIn)); // CraftBukkit - Use dimension
return true;
}
else
@@ -1136,10 +1399,18 @@
public Explosion newExplosion(@Nullable Entity entityIn, double x, double y, double z, float strength, boolean isFlaming, boolean isSmoking)
{
+ Explosion explosion = super.newExplosion(entityIn, x, y, z, strength, isFlaming, isSmoking);
+
+ if (explosion.wasCanceled) {
+ return explosion;
+ }
+ if (net.minecraftforge.event.ForgeEventFactory.onExplosionStart(this, explosion)) return explosion;
+ /* Remove
Explosion explosion = new Explosion(this, entityIn, x, y, z, strength, isFlaming, isSmoking);
explosion.doExplosionA();
explosion.doExplosionB(false);
-
+ */
+ // CraftBukkit - TODO: Check if explosions are still properly implemented
if (!isSmoking)
{
explosion.clearAffectedBlockPositions();
@@ -1182,7 +1453,8 @@
{
if (this.fireBlockEvent(blockeventdata))
{
- this.mcServer.getPlayerList().sendToAllNearExcept((EntityPlayer)null, (double)blockeventdata.getPosition().getX(), (double)blockeventdata.getPosition().getY(), (double)blockeventdata.getPosition().getZ(), 64.0D, this.provider.getDimensionType().getId(), new SPacketBlockAction(blockeventdata.getPosition(), blockeventdata.getBlock(), blockeventdata.getEventID(), blockeventdata.getEventParameter()));
+ // CraftBukkit - this.provider.dimension -> this.dimension
+ this.mcServer.getPlayerList().sendToAllNearExcept((EntityPlayer)null, (double)blockeventdata.getPosition().getX(), (double)blockeventdata.getPosition().getY(), (double)blockeventdata.getPosition().getZ(), 64.0D, dimension, new SPacketBlockAction(blockeventdata.getPosition(), blockeventdata.getBlock(), blockeventdata.getEventID(), blockeventdata.getEventParameter()));
}
}
@@ -1208,27 +1480,31 @@
if (this.prevRainingStrength != this.rainingStrength)
{
- this.mcServer.getPlayerList().sendPacketToAllPlayersInDimension(new SPacketChangeGameState(7, this.rainingStrength), this.provider.getDimensionType().getId());
+ this.mcServer.getPlayerList().sendPacketToAllPlayersInDimension(new SPacketChangeGameState(7, this.rainingStrength), this.provider.getDimension());
}
if (this.prevThunderingStrength != this.thunderingStrength)
{
- this.mcServer.getPlayerList().sendPacketToAllPlayersInDimension(new SPacketChangeGameState(8, this.thunderingStrength), this.provider.getDimensionType().getId());
+ this.mcServer.getPlayerList().sendPacketToAllPlayersInDimension(new SPacketChangeGameState(8, this.thunderingStrength), this.provider.getDimension());
}
+ /* 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)
{
- this.mcServer.getPlayerList().sendPacketToAllPlayers(new SPacketChangeGameState(2, 0.0F));
+ this.mcServer.getPlayerList().sendPacketToAllPlayersInDimension(new SPacketChangeGameState(2, 0.0F), this.provider.getDimension());
}
else
{
- this.mcServer.getPlayerList().sendPacketToAllPlayers(new SPacketChangeGameState(1, 0.0F));
+ this.mcServer.getPlayerList().sendPacketToAllPlayersInDimension(new SPacketChangeGameState(1, 0.0F), this.provider.getDimension());
}
- this.mcServer.getPlayerList().sendPacketToAllPlayers(new SPacketChangeGameState(7, this.rainingStrength));
- this.mcServer.getPlayerList().sendPacketToAllPlayers(new SPacketChangeGameState(8, this.thunderingStrength));
+ this.mcServer.getPlayerList().sendPacketToAllPlayersInDimension(new SPacketChangeGameState(7, this.rainingStrength), this.provider.getDimension());
+ this.mcServer.getPlayerList().sendPacketToAllPlayersInDimension(new SPacketChangeGameState(8, this.thunderingStrength), this.provider.getDimension());
}
}
@@ -1265,11 +1541,18 @@
public void spawnParticle(EnumParticleTypes particleType, boolean longDistance, double xCoord, double yCoord, double zCoord, int numberOfParticles, double xOffset, double yOffset, double zOffset, double particleSpeed, int... particleArguments)
{
+ // CraftBukkit - visibility api support
+ sendParticles(null, particleType, longDistance, xCoord, yCoord, zCoord, numberOfParticles, xOffset, yOffset, zOffset, particleSpeed, particleArguments);
+ }
+
+ public void sendParticles(@Nullable EntityPlayerMP sender, EnumParticleTypes particleType, boolean longDistance, double xCoord, double yCoord, double zCoord, int numberOfParticles, double xOffset, double yOffset, double zOffset, double particleSpeed, int... particleArguments) {
+ // CraftBukkit end
SPacketParticles spacketparticles = new SPacketParticles(particleType, longDistance, (float)xCoord, (float)yCoord, (float)zCoord, (float)xOffset, (float)yOffset, (float)zOffset, (float)particleSpeed, numberOfParticles, particleArguments);
for (int i = 0; i < this.playerEntities.size(); ++i)
{
EntityPlayerMP entityplayermp = (EntityPlayerMP)this.playerEntities.get(i);
+ if (sender != null && !entityplayermp.getBukkitEntity().canSee(sender.getBukkitEntity())) continue;
this.sendPacketWithinDistance(entityplayermp, longDistance, xCoord, yCoord, zCoord, spacketparticles);
}
}
@@ -1323,6 +1606,11 @@
return this.functionManager;
}
+ public File getChunkSaveLocation()
+ {
+ return ((net.minecraft.world.chunk.storage.AnvilChunkLoader)getChunkProvider().chunkLoader).chunkSaveLocation;
+ }
+
static class ServerBlockEventList extends ArrayList<BlockEventData>
{
private ServerBlockEventList()