Paper/nms-patches/WorldServer.patch
Pokechu22 e20928f7da SPIGOT-2726: Fix duplicate UUID check not always running
World.addEntity(Entity entity) calls addEntity(entity, SpawnReason.DEFAULT), which contains the code that was originally in addEntity (and some event code).

However, WorldServer previously only had addEntity(Entity entity), so if addEntity(Entity entity, SpawnReason spawnreason) was called directly, the UUID check that's found in it (the call to 'i') is skipped.  This happens, among other places, in ChunkRegionLoader.spawnEntity (which /summon uses).

I fixed this by making WorldServer override the SpawnReason version, rather than the regular version.  This is safe to do because the World version calls the SpawnReason version - it's not necessary to do the same thing in WorldServer.
2016-10-16 19:42:23 +11:00

651 lines
30 KiB
Diff

--- a/net/minecraft/server/WorldServer.java
+++ b/net/minecraft/server/WorldServer.java
@@ -19,14 +19,26 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+// CraftBukkit start
+import java.util.logging.Level;
+
+import org.bukkit.WeatherType;
+import org.bukkit.block.BlockState;
+import org.bukkit.craftbukkit.util.HashTreeSet;
+
+import org.bukkit.event.block.BlockFormEvent;
+import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
+import org.bukkit.event.weather.LightningStrikeEvent;
+// CraftBukkit end
+
public class WorldServer extends World implements IAsyncTaskHandler {
private static final Logger a = LogManager.getLogger();
private final MinecraftServer server;
public EntityTracker tracker;
private final PlayerChunkMap manager;
- private final Set<NextTickListEntry> nextTickListHash = Sets.newHashSet();
- private final TreeSet<NextTickListEntry> nextTickList = new TreeSet();
+ // private final Set<NextTickListEntry> nextTickListHash = Sets.newHashSet();
+ private final HashTreeSet<NextTickListEntry> nextTickList = new HashTreeSet<NextTickListEntry>(); // CraftBukkit - HashTreeSet
private final Map<UUID, Entity> entitiesByUUID = Maps.newHashMap();
public boolean savingDisabled;
private boolean O;
@@ -38,14 +50,22 @@
private int T;
private final List<NextTickListEntry> U = Lists.newArrayList();
- public WorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, WorldData worlddata, int i, MethodProfiler methodprofiler) {
- super(idatamanager, worlddata, DimensionManager.a(i).d(), methodprofiler, false);
+ // CraftBukkit start
+ public final int dimension;
+
+ // Add env and gen to constructor
+ public WorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, WorldData worlddata, int i, MethodProfiler methodprofiler, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) {
+ super(idatamanager, worlddata, DimensionManager.a(env.getId()).d(), methodprofiler, false, gen, env);
+ this.dimension = i;
+ this.pvpMode = minecraftserver.getPVP();
+ worlddata.world = this;
+ // CraftBukkit end
this.server = minecraftserver;
this.tracker = new EntityTracker(this);
this.manager = new PlayerChunkMap(this);
this.worldProvider.a((World) this);
this.chunkProvider = this.n();
- this.portalTravelAgent = new PortalTravelAgent(this);
+ this.portalTravelAgent = new org.bukkit.craftbukkit.CraftTravelAgent(this); // CraftBukkit
this.H();
this.I();
this.getWorldBorder().a(minecraftserver.aD());
@@ -64,6 +84,7 @@
this.villages.a((World) this);
}
+ if (getServer().getScoreboardManager() == null) { // CraftBukkit
this.scoreboard = new ScoreboardServer(this.server);
PersistentScoreboard persistentscoreboard = (PersistentScoreboard) this.worldMaps.get(PersistentScoreboard.class, "scoreboard");
@@ -74,6 +95,11 @@
persistentscoreboard.a(this.scoreboard);
((ScoreboardServer) this.scoreboard).a((Runnable) (new RunnableSaveScoreboard(persistentscoreboard)));
+ // CraftBukkit start
+ } else {
+ this.scoreboard = getServer().getScoreboardManager().getMainScoreboard().getHandle();
+ }
+ // CraftBukkit end
this.B = new LootTableRegistry(new File(new File(this.dataManager.getDirectory(), "data"), "loot_tables"));
this.getWorldBorder().setCenter(this.worldData.B(), this.worldData.C());
this.getWorldBorder().setDamageAmount(this.worldData.H());
@@ -86,9 +112,98 @@
this.getWorldBorder().setSize(this.worldData.D());
}
+ // CraftBukkit start
+ if (generator != null) {
+ getWorld().getPopulators().addAll(generator.getDefaultPopulators(getWorld()));
+ }
+ // CraftBukkit end
+
return this;
}
+ // CraftBukkit start
+ @Override
+ public TileEntity getTileEntity(BlockPosition pos) {
+ TileEntity result = super.getTileEntity(pos);
+ Block type = getType(pos).getBlock();
+
+ if (type == Blocks.CHEST) {
+ if (!(result instanceof TileEntityChest)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ } else if (type == Blocks.FURNACE) {
+ if (!(result instanceof TileEntityFurnace)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ } else if (type == Blocks.DROPPER) {
+ if (!(result instanceof TileEntityDropper)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ } else if (type == Blocks.DISPENSER) {
+ if (!(result instanceof TileEntityDispenser)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ } else if (type == Blocks.JUKEBOX) {
+ if (!(result instanceof BlockJukeBox.TileEntityRecordPlayer)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ } else if (type == Blocks.NOTEBLOCK) {
+ if (!(result instanceof TileEntityNote)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ } else if (type == Blocks.MOB_SPAWNER) {
+ if (!(result instanceof TileEntityMobSpawner)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ } else if ((type == Blocks.STANDING_SIGN) || (type == Blocks.WALL_SIGN)) {
+ if (!(result instanceof TileEntitySign)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ } else if (type == Blocks.ENDER_CHEST) {
+ if (!(result instanceof TileEntityEnderChest)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ } else if (type == Blocks.BREWING_STAND) {
+ if (!(result instanceof TileEntityBrewingStand)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ } else if (type == Blocks.BEACON) {
+ if (!(result instanceof TileEntityBeacon)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ } else if (type == Blocks.HOPPER) {
+ if (!(result instanceof TileEntityHopper)) {
+ result = fixTileEntity(pos, type, result);
+ }
+ }
+
+ return result;
+ }
+
+ private TileEntity fixTileEntity(BlockPosition 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.getMaterial(Block.getId(type)).toString(), found});
+
+ if (type instanceof ITileEntity) {
+ TileEntity replacement = ((ITileEntity) type).a(this, type.toLegacyData(this.getType(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.worldProvider.canSpawn(x, z);
+ }
+ }
+ // CraftBukkit end
+
public void doTick() {
super.doTick();
if (this.getWorldData().isHardcore() && this.getDifficulty() != EnumDifficulty.HARD) {
@@ -106,9 +221,11 @@
this.f();
}
- this.methodProfiler.a("mobSpawner");
- if (this.getGameRules().getBoolean("doMobSpawning") && this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES) {
- this.spawnerCreature.a(this, this.allowMonsters, this.allowAnimals, this.worldData.getTime() % 400L == 0L);
+ // CraftBukkit start - Only call spawner if we have players online and the world allows for mobs or animals
+ long time = this.worldData.getTime();
+ if (this.getGameRules().getBoolean("doMobSpawning") && this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES && (this.allowMonsters || this.allowAnimals) && (this instanceof WorldServer && this.players.size() > 0)) {
+ this.spawnerCreature.a(this, this.allowMonsters && (this.ticksPerMonsterSpawns != 0 && time % this.ticksPerMonsterSpawns == 0L), this.allowAnimals && (this.ticksPerAnimalSpawns != 0 && time % this.ticksPerAnimalSpawns == 0L), this.worldData.getTime() % 400L == 0L);
+ // CraftBukkit end
}
this.methodProfiler.c("chunkSource");
@@ -137,6 +254,8 @@
this.portalTravelAgent.a(this.getTime());
this.methodProfiler.b();
this.ao();
+
+ this.getWorld().processChunkGC(); // CraftBukkit
}
@Nullable
@@ -164,7 +283,7 @@
if (entityhuman.isSpectator()) {
++i;
- } else if (entityhuman.isSleeping()) {
+ } else if (entityhuman.isSleeping() || entityhuman.fauxSleeping) {
++j;
}
}
@@ -190,25 +309,46 @@
}
private void c() {
- this.worldData.setWeatherDuration(0);
this.worldData.setStorm(false);
- this.worldData.setThunderDuration(0);
+ // CraftBukkit start
+ // If we stop due to everyone sleeping we should reset the weather duration to some other random value.
+ // Not that everyone ever manages to get the whole server to sleep at the same time....
+ if (!this.worldData.hasStorm()) {
+ this.worldData.setWeatherDuration(0);
+ }
+ // CraftBukkit end
this.worldData.setThundering(false);
+ // CraftBukkit start
+ // If we stop due to everyone sleeping we should reset the weather duration to some other random value.
+ // Not that everyone ever manages to get the whole server to sleep at the same time....
+ if (!this.worldData.isThundering()) {
+ this.worldData.setThunderDuration(0);
+ }
+ // CraftBukkit end
}
public boolean everyoneDeeplySleeping() {
if (this.O && !this.isClientSide) {
Iterator iterator = this.players.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;
+
EntityHuman entityhuman;
do {
if (!iterator.hasNext()) {
- return true;
+ return foundActualSleepers;
}
entityhuman = (EntityHuman) iterator.next();
- } while (entityhuman.isSpectator() || entityhuman.isDeeplySleeping());
+
+ // CraftBukkit start
+ if (entityhuman.isDeeplySleeping()) {
+ foundActualSleepers = true;
+ }
+ } while (!entityhuman.isSpectator() || entityhuman.isDeeplySleeping() || entityhuman.fauxSleeping);
+ // CraftBukkit end
return false;
} else {
@@ -279,7 +419,7 @@
entityhorse.y(true);
entityhorse.setAgeRaw(0);
entityhorse.setPosition((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ());
- this.addEntity(entityhorse);
+ this.addEntity(entityhorse, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit
this.strikeLightning(new EntityLightning(this, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), true));
} else {
this.strikeLightning(new EntityLightning(this, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), false));
@@ -295,11 +435,29 @@
BlockPosition blockposition1 = blockposition.down();
if (this.v(blockposition1)) {
- this.setTypeUpdate(blockposition1, Blocks.ICE.getBlockData());
+ // CraftBukkit start
+ BlockState blockState = this.getWorld().getBlockAt(blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()).getState();
+ blockState.setTypeId(Block.getId(Blocks.ICE));
+
+ BlockFormEvent iceBlockForm = new BlockFormEvent(blockState.getBlock(), blockState);
+ this.getServer().getPluginManager().callEvent(iceBlockForm);
+ if (!iceBlockForm.isCancelled()) {
+ blockState.update(true);
+ }
+ // CraftBukkit end
}
if (flag && this.f(blockposition, true)) {
- this.setTypeUpdate(blockposition, Blocks.SNOW_LAYER.getBlockData());
+ // CraftBukkit start
+ BlockState blockState = this.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()).getState();
+ blockState.setTypeId(Block.getId(Blocks.SNOW_LAYER));
+
+ BlockFormEvent snow = new BlockFormEvent(blockState.getBlock(), blockState);
+ this.getServer().getPluginManager().callEvent(snow);
+ if (!snow.isCancelled()) {
+ blockState.update(true);
+ }
+ // CraftBukkit end
}
if (flag && this.getBiome(blockposition1).d()) {
@@ -374,7 +532,7 @@
public boolean b(BlockPosition blockposition, Block block) {
NextTickListEntry nextticklistentry = new NextTickListEntry(blockposition, block);
- return this.nextTickListHash.contains(nextticklistentry);
+ return this.nextTickList.contains(nextticklistentry); // CraftBukkit
}
public void a(BlockPosition blockposition, Block block, int i) {
@@ -413,8 +571,8 @@
nextticklistentry.a(j);
}
- if (!this.nextTickListHash.contains(nextticklistentry)) {
- this.nextTickListHash.add(nextticklistentry);
+ // CraftBukkit - use nextTickList
+ if (!this.nextTickList.contains(nextticklistentry)) {
this.nextTickList.add(nextticklistentry);
}
}
@@ -436,15 +594,15 @@
nextticklistentry.a((long) i + this.worldData.getTime());
}
- if (!this.nextTickListHash.contains(nextticklistentry)) {
- this.nextTickListHash.add(nextticklistentry);
+ // CraftBukkit - use nextTickList
+ if (!this.nextTickList.contains(nextticklistentry)) {
this.nextTickList.add(nextticklistentry);
}
}
public void tickEntities() {
- if (this.players.isEmpty()) {
+ if (false && this.players.isEmpty()) { // CraftBukkit - this prevents entity cleanup, other issues on servers with no players
if (this.emptyTime++ >= 300) {
return;
}
@@ -514,11 +672,17 @@
} else {
int i = this.nextTickList.size();
- if (i != this.nextTickListHash.size()) {
+ if (false) { // CraftBukkit
throw new IllegalStateException("TickNextTick list out of synch");
} else {
if (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.methodProfiler.a("cleaning");
@@ -531,8 +695,9 @@
break;
}
+ // CraftBukkit - use nextTickList
this.nextTickList.remove(nextticklistentry);
- this.nextTickListHash.remove(nextticklistentry);
+ // this.nextTickListHash.remove(nextticklistentry);
this.U.add(nextticklistentry);
}
@@ -602,7 +767,7 @@
if (blockposition.getX() >= structureboundingbox.a && blockposition.getX() < structureboundingbox.d && blockposition.getZ() >= structureboundingbox.c && blockposition.getZ() < structureboundingbox.f) {
if (flag) {
if (i == 0) {
- this.nextTickListHash.remove(nextticklistentry);
+ // this.nextTickListHash.remove(nextticklistentry); // CraftBukkit - removed
}
iterator.remove();
@@ -620,6 +785,7 @@
return arraylist;
}
+ /* CraftBukkit start - We prevent spawning in general, so this butchering is not needed
public void entityJoinedWorld(Entity entity, boolean flag) {
if (!this.getSpawnAnimals() && (entity instanceof EntityAnimal || entity instanceof EntityWaterAnimal)) {
entity.die();
@@ -631,6 +797,7 @@
super.entityJoinedWorld(entity, flag);
}
+ // CraftBukkit end */
private boolean getSpawnNPCs() {
return this.server.getSpawnNPCs();
@@ -643,7 +810,54 @@
protected IChunkProvider n() {
IChunkLoader ichunkloader = this.dataManager.createChunkLoader(this.worldProvider);
- return new ChunkProviderServer(this, ichunkloader, this.worldProvider.getChunkGenerator());
+ // 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.worldProvider instanceof WorldProviderHell) {
+ gen = new org.bukkit.craftbukkit.generator.NetherChunkGenerator(this, this.getSeed());
+ } else if (this.worldProvider instanceof WorldProviderTheEnd) {
+ gen = new org.bukkit.craftbukkit.generator.SkyLandsChunkGenerator(this, this.getSeed());
+ } else {
+ gen = new org.bukkit.craftbukkit.generator.NormalChunkGenerator(this, this.getSeed());
+ }
+
+ return new ChunkProviderServer(this, ichunkloader, gen);
+ // CraftBukkit end
+ }
+
+ 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 = getChunkAt(chunkX, chunkZ);
+ if (chunk == null) {
+ continue;
+ }
+ for (Object te : chunk.tileEntities.values()) {
+ TileEntity tileentity = (TileEntity) te;
+ if ((tileentity.position.getX() >= i) && (tileentity.position.getY() >= j) && (tileentity.position.getZ() >= k) && (tileentity.position.getX() < l) && (tileentity.position.getY() < i1) && (tileentity.position.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 a(EntityHuman entityhuman, BlockPosition blockposition) {
@@ -705,6 +919,23 @@
int j = this.worldProvider.getSeaLevel();
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.worldData.getName() + " to be in another world (" + spawn.getWorld().getName() + ")");
+ } else {
+ this.worldData.setSpawn(new BlockPosition(spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ()));
+ this.isLoading = false;
+ return;
+ }
+ }
+ }
+ // CraftBukkit end
+
if (blockposition != null) {
i = blockposition.getX();
k = blockposition.getZ();
@@ -714,7 +945,7 @@
int l = 0;
- while (!this.worldProvider.canSpawn(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);
++l;
@@ -755,6 +986,7 @@
ChunkProviderServer chunkproviderserver = this.getChunkProviderServer();
if (chunkproviderserver.e()) {
+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit
if (iprogressupdate != null) {
iprogressupdate.a("Saving level");
}
@@ -765,7 +997,8 @@
}
chunkproviderserver.a(flag);
- ArrayList arraylist = Lists.newArrayList(chunkproviderserver.a());
+ // CraftBukkit - ArrayList -> Collection
+ Collection arraylist = chunkproviderserver.a();
Iterator iterator = arraylist.iterator();
while (iterator.hasNext()) {
@@ -800,6 +1033,12 @@
}
}
+ // CraftBukkit start - Save secondary data for nether/end
+ if (this instanceof SecondaryWorldServer) {
+ ((SecondaryWorldServer) this).c();
+ }
+ // CraftBukkit end
+
this.worldData.a(this.getWorldBorder().getSize());
this.worldData.d(this.getWorldBorder().getCenterX());
this.worldData.c(this.getWorldBorder().getCenterZ());
@@ -813,9 +1052,13 @@
this.worldMaps.a();
}
- public boolean addEntity(Entity entity) {
- return this.i(entity) ? super.addEntity(entity) : false;
+ // CraftBukkit start
+ public boolean addEntity(Entity entity, SpawnReason spawnReason) { // Changed signature, added SpawnReason
+ // World.addEntity(Entity) will call this, and we still want to perform
+ // existing entity checking when it's called with a SpawnReason
+ return this.i(entity) ? super.addEntity(entity, spawnReason) : false;
}
+ // CraftBukkit end
public void a(Collection<Entity> collection) {
ArrayList arraylist = Lists.newArrayList(collection);
@@ -834,7 +1077,7 @@
private boolean i(Entity entity) {
if (entity.dead) {
- WorldServer.a.warn("Tried to add entity {} but it was marked as removed already", new Object[] { EntityTypes.b(entity)});
+ // WorldServer.a.warn("Tried to add entity {} but it was marked as removed already", new Object[] { EntityTypes.b(entity)}); // CraftBukkit
return false;
} else {
UUID uuid = entity.getUniqueID();
@@ -846,7 +1089,7 @@
this.f.remove(entity1);
} else {
if (!(entity instanceof EntityHuman)) {
- WorldServer.a.warn("Keeping entity {} that already exists with UUID {}", new Object[] { EntityTypes.b(entity1), uuid.toString()});
+ // WorldServer.a.warn("Keeping entity {} that already exists with UUID {}", new Object[] { EntityTypes.b(entity1), uuid.toString()}); // CraftBukkit
return false;
}
@@ -899,8 +1142,16 @@
}
public boolean strikeLightning(Entity entity) {
+ // CraftBukkit start
+ LightningStrikeEvent lightning = new LightningStrikeEvent(this.getWorld(), (org.bukkit.entity.LightningStrike) entity.getBukkitEntity());
+ this.getServer().getPluginManager().callEvent(lightning);
+
+ if (lightning.isCancelled()) {
+ return false;
+ }
+ // CraftBukkit end
if (super.strikeLightning(entity)) {
- this.server.getPlayerList().sendPacketNearby((EntityHuman) null, entity.locX, entity.locY, entity.locZ, 512.0D, this.worldProvider.getDimensionManager().getDimensionID(), new PacketPlayOutSpawnEntityWeather(entity));
+ this.server.getPlayerList().sendPacketNearby((EntityHuman) null, entity.locX, entity.locY, entity.locZ, 512.0D, dimension, new PacketPlayOutSpawnEntityWeather(entity)); // CraftBukkit - Use dimension
return true;
} else {
return false;
@@ -916,10 +1167,20 @@
}
public Explosion createExplosion(@Nullable Entity entity, double d0, double d1, double d2, float f, boolean flag, boolean flag1) {
+ // CraftBukkit start
+ Explosion explosion = super.createExplosion(entity, d0, d1, d2, f, flag, flag1);
+
+ if (explosion.wasCanceled) {
+ return explosion;
+ }
+
+ /* Remove
Explosion explosion = new Explosion(this, entity, d0, d1, d2, f, flag, flag1);
explosion.a();
explosion.a(false);
+ */
+ // CraftBukkit end - TODO: Check if explosions are still properly implemented
if (!flag1) {
explosion.clearBlocks();
}
@@ -965,7 +1226,8 @@
BlockActionData blockactiondata = (BlockActionData) iterator.next();
if (this.a(blockactiondata)) {
- this.server.getPlayerList().sendPacketNearby((EntityHuman) null, (double) blockactiondata.a().getX(), (double) blockactiondata.a().getY(), (double) blockactiondata.a().getZ(), 64.0D, this.worldProvider.getDimensionManager().getDimensionID(), new PacketPlayOutBlockAction(blockactiondata.a(), blockactiondata.d(), blockactiondata.b(), blockactiondata.c()));
+ // CraftBukkit - this.worldProvider.dimension -> this.dimension
+ this.server.getPlayerList().sendPacketNearby((EntityHuman) null, (double) blockactiondata.a().getX(), (double) blockactiondata.a().getY(), (double) blockactiondata.a().getZ(), 64.0D, dimension, new PacketPlayOutBlockAction(blockactiondata.a(), blockactiondata.d(), blockactiondata.b(), blockactiondata.c()));
}
}
@@ -988,6 +1250,7 @@
boolean flag = this.W();
super.t();
+ /* CraftBukkit start
if (this.n != this.o) {
this.server.getPlayerList().a((Packet) (new PacketPlayOutGameStateChange(7, this.o)), this.worldProvider.getDimensionManager().getDimensionID());
}
@@ -1006,6 +1269,21 @@
this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(7, this.o));
this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(8, this.q));
}
+ // */
+ if (flag != this.W()) {
+ // Only send weather packets to those affected
+ for (int i = 0; i < this.players.size(); ++i) {
+ if (((EntityPlayer) this.players.get(i)).world == this) {
+ ((EntityPlayer) this.players.get(i)).setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false);
+ }
+ }
+ }
+ for (int i = 0; i < this.players.size(); ++i) {
+ if (((EntityPlayer) this.players.get(i)).world == this) {
+ ((EntityPlayer) this.players.get(i)).updateWeather(this.n, this.o, this.p, this.q);
+ }
+ }
+ // CraftBukkit end
}
@@ -1035,10 +1313,20 @@
}
public void a(EnumParticle enumparticle, boolean flag, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, int... aint) {
+ // CraftBukkit - visibility api support
+ sendParticles(null, enumparticle, flag, d0, d1, d2, i, d3, d4, d5, d6, aint);
+ }
+
+ public void sendParticles(EntityPlayer sender, EnumParticle enumparticle, boolean flag, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, int... aint) {
+ // CraftBukkit end
PacketPlayOutWorldParticles packetplayoutworldparticles = new PacketPlayOutWorldParticles(enumparticle, flag, (float) d0, (float) d1, (float) d2, (float) d3, (float) d4, (float) d5, (float) d6, i, aint);
for (int j = 0; j < this.players.size(); ++j) {
EntityPlayer entityplayer = (EntityPlayer) this.players.get(j);
+ if (sender != null && !entityplayer.getBukkitEntity().canSee(sender.getBukkitEntity())) continue; // CraftBukkit
+ BlockPosition blockposition = entityplayer.getChunkCoordinates();
+ double d7 = blockposition.distanceSquared(d0, d1, d2);
+
this.a(entityplayer, flag, d0, d1, d2, packetplayoutworldparticles);
}