mirror of
https://github.com/barkeser2002/CatServer.git
synced 2026-09-25 01:39:52 +03:00
859 lines
42 KiB
Diff
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()
|