Commits

pokechu22 authored and md_5 committed e20928f7da2
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.
No tags

nms-patches/WorldServer.patch

Modified
1 1 --- a/net/minecraft/server/WorldServer.java
2 2 +++ b/net/minecraft/server/WorldServer.java
3 -@@ -19,14 +19,25 @@
3 +@@ -19,14 +19,26 @@
4 4 import org.apache.logging.log4j.LogManager;
5 5 import org.apache.logging.log4j.Logger;
6 6
7 7 +// CraftBukkit start
8 8 +import java.util.logging.Level;
9 9 +
10 10 +import org.bukkit.WeatherType;
11 11 +import org.bukkit.block.BlockState;
12 12 +import org.bukkit.craftbukkit.util.HashTreeSet;
13 13 +
14 14 +import org.bukkit.event.block.BlockFormEvent;
15 ++import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
15 16 +import org.bukkit.event.weather.LightningStrikeEvent;
16 17 +// CraftBukkit end
17 18 +
18 19 public class WorldServer extends World implements IAsyncTaskHandler {
19 20
20 21 private static final Logger a = LogManager.getLogger();
21 22 private final MinecraftServer server;
22 23 public EntityTracker tracker;
23 24 private final PlayerChunkMap manager;
24 25 - private final Set<NextTickListEntry> nextTickListHash = Sets.newHashSet();
25 26 - private final TreeSet<NextTickListEntry> nextTickList = new TreeSet();
26 27 + // private final Set<NextTickListEntry> nextTickListHash = Sets.newHashSet();
27 28 + private final HashTreeSet<NextTickListEntry> nextTickList = new HashTreeSet<NextTickListEntry>(); // CraftBukkit - HashTreeSet
28 29 private final Map<UUID, Entity> entitiesByUUID = Maps.newHashMap();
29 30 public boolean savingDisabled;
30 31 private boolean O;
31 -@@ -38,14 +49,22 @@
32 +@@ -38,14 +50,22 @@
32 33 private int T;
33 34 private final List<NextTickListEntry> U = Lists.newArrayList();
34 35
35 36 - public WorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, WorldData worlddata, int i, MethodProfiler methodprofiler) {
36 37 - super(idatamanager, worlddata, DimensionManager.a(i).d(), methodprofiler, false);
37 38 + // CraftBukkit start
38 39 + public final int dimension;
39 40 +
40 41 + // Add env and gen to constructor
41 42 + public WorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, WorldData worlddata, int i, MethodProfiler methodprofiler, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) {
47 48 this.server = minecraftserver;
48 49 this.tracker = new EntityTracker(this);
49 50 this.manager = new PlayerChunkMap(this);
50 51 this.worldProvider.a((World) this);
51 52 this.chunkProvider = this.n();
52 53 - this.portalTravelAgent = new PortalTravelAgent(this);
53 54 + this.portalTravelAgent = new org.bukkit.craftbukkit.CraftTravelAgent(this); // CraftBukkit
54 55 this.H();
55 56 this.I();
56 57 this.getWorldBorder().a(minecraftserver.aD());
57 -@@ -64,6 +83,7 @@
58 +@@ -64,6 +84,7 @@
58 59 this.villages.a((World) this);
59 60 }
60 61
61 62 + if (getServer().getScoreboardManager() == null) { // CraftBukkit
62 63 this.scoreboard = new ScoreboardServer(this.server);
63 64 PersistentScoreboard persistentscoreboard = (PersistentScoreboard) this.worldMaps.get(PersistentScoreboard.class, "scoreboard");
64 65
65 -@@ -74,6 +94,11 @@
66 +@@ -74,6 +95,11 @@
66 67
67 68 persistentscoreboard.a(this.scoreboard);
68 69 ((ScoreboardServer) this.scoreboard).a((Runnable) (new RunnableSaveScoreboard(persistentscoreboard)));
69 70 + // CraftBukkit start
70 71 + } else {
71 72 + this.scoreboard = getServer().getScoreboardManager().getMainScoreboard().getHandle();
72 73 + }
73 74 + // CraftBukkit end
74 75 this.B = new LootTableRegistry(new File(new File(this.dataManager.getDirectory(), "data"), "loot_tables"));
75 76 this.getWorldBorder().setCenter(this.worldData.B(), this.worldData.C());
76 77 this.getWorldBorder().setDamageAmount(this.worldData.H());
77 -@@ -86,9 +111,98 @@
78 +@@ -86,9 +112,98 @@
78 79 this.getWorldBorder().setSize(this.worldData.D());
79 80 }
80 81
81 82 + // CraftBukkit start
82 83 + if (generator != null) {
83 84 + getWorld().getPopulators().addAll(generator.getDefaultPopulators(getWorld()));
84 85 + }
85 86 + // CraftBukkit end
86 87 +
87 88 return this;
166 167 + return this.generator.canSpawn(this.getWorld(), x, z);
167 168 + } else {
168 169 + return this.worldProvider.canSpawn(x, z);
169 170 + }
170 171 + }
171 172 + // CraftBukkit end
172 173 +
173 174 public void doTick() {
174 175 super.doTick();
175 176 if (this.getWorldData().isHardcore() && this.getDifficulty() != EnumDifficulty.HARD) {
176 -@@ -106,9 +220,11 @@
177 +@@ -106,9 +221,11 @@
177 178 this.f();
178 179 }
179 180
180 181 - this.methodProfiler.a("mobSpawner");
181 182 - if (this.getGameRules().getBoolean("doMobSpawning") && this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES) {
182 183 - this.spawnerCreature.a(this, this.allowMonsters, this.allowAnimals, this.worldData.getTime() % 400L == 0L);
183 184 + // CraftBukkit start - Only call spawner if we have players online and the world allows for mobs or animals
184 185 + long time = this.worldData.getTime();
185 186 + if (this.getGameRules().getBoolean("doMobSpawning") && this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES && (this.allowMonsters || this.allowAnimals) && (this instanceof WorldServer && this.players.size() > 0)) {
186 187 + 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);
187 188 + // CraftBukkit end
188 189 }
189 190
190 191 this.methodProfiler.c("chunkSource");
191 -@@ -137,6 +253,8 @@
192 +@@ -137,6 +254,8 @@
192 193 this.portalTravelAgent.a(this.getTime());
193 194 this.methodProfiler.b();
194 195 this.ao();
195 196 +
196 197 + this.getWorld().processChunkGC(); // CraftBukkit
197 198 }
198 199
199 200 @Nullable
200 -@@ -164,7 +282,7 @@
201 +@@ -164,7 +283,7 @@
201 202
202 203 if (entityhuman.isSpectator()) {
203 204 ++i;
204 205 - } else if (entityhuman.isSleeping()) {
205 206 + } else if (entityhuman.isSleeping() || entityhuman.fauxSleeping) {
206 207 ++j;
207 208 }
208 209 }
209 -@@ -190,25 +308,46 @@
210 +@@ -190,25 +309,46 @@
210 211 }
211 212
212 213 private void c() {
213 214 - this.worldData.setWeatherDuration(0);
214 215 this.worldData.setStorm(false);
215 216 - this.worldData.setThunderDuration(0);
216 217 + // CraftBukkit start
217 218 + // If we stop due to everyone sleeping we should reset the weather duration to some other random value.
218 219 + // Not that everyone ever manages to get the whole server to sleep at the same time....
219 220 + if (!this.worldData.hasStorm()) {
250 251 +
251 252 + // CraftBukkit start
252 253 + if (entityhuman.isDeeplySleeping()) {
253 254 + foundActualSleepers = true;
254 255 + }
255 256 + } while (!entityhuman.isSpectator() || entityhuman.isDeeplySleeping() || entityhuman.fauxSleeping);
256 257 + // CraftBukkit end
257 258
258 259 return false;
259 260 } else {
260 -@@ -279,7 +418,7 @@
261 +@@ -279,7 +419,7 @@
261 262 entityhorse.y(true);
262 263 entityhorse.setAgeRaw(0);
263 264 entityhorse.setPosition((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ());
264 265 - this.addEntity(entityhorse);
265 266 + this.addEntity(entityhorse, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit
266 267 this.strikeLightning(new EntityLightning(this, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), true));
267 268 } else {
268 269 this.strikeLightning(new EntityLightning(this, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), false));
269 -@@ -295,11 +434,29 @@
270 +@@ -295,11 +435,29 @@
270 271 BlockPosition blockposition1 = blockposition.down();
271 272
272 273 if (this.v(blockposition1)) {
273 274 - this.setTypeUpdate(blockposition1, Blocks.ICE.getBlockData());
274 275 + // CraftBukkit start
275 276 + BlockState blockState = this.getWorld().getBlockAt(blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()).getState();
276 277 + blockState.setTypeId(Block.getId(Blocks.ICE));
277 278 +
278 279 + BlockFormEvent iceBlockForm = new BlockFormEvent(blockState.getBlock(), blockState);
279 280 + this.getServer().getPluginManager().callEvent(iceBlockForm);
291 292 +
292 293 + BlockFormEvent snow = new BlockFormEvent(blockState.getBlock(), blockState);
293 294 + this.getServer().getPluginManager().callEvent(snow);
294 295 + if (!snow.isCancelled()) {
295 296 + blockState.update(true);
296 297 + }
297 298 + // CraftBukkit end
298 299 }
299 300
300 301 if (flag && this.getBiome(blockposition1).d()) {
301 -@@ -374,7 +531,7 @@
302 +@@ -374,7 +532,7 @@
302 303 public boolean b(BlockPosition blockposition, Block block) {
303 304 NextTickListEntry nextticklistentry = new NextTickListEntry(blockposition, block);
304 305
305 306 - return this.nextTickListHash.contains(nextticklistentry);
306 307 + return this.nextTickList.contains(nextticklistentry); // CraftBukkit
307 308 }
308 309
309 310 public void a(BlockPosition blockposition, Block block, int i) {
310 -@@ -413,8 +570,8 @@
311 +@@ -413,8 +571,8 @@
311 312 nextticklistentry.a(j);
312 313 }
313 314
314 315 - if (!this.nextTickListHash.contains(nextticklistentry)) {
315 316 - this.nextTickListHash.add(nextticklistentry);
316 317 + // CraftBukkit - use nextTickList
317 318 + if (!this.nextTickList.contains(nextticklistentry)) {
318 319 this.nextTickList.add(nextticklistentry);
319 320 }
320 321 }
321 -@@ -436,15 +593,15 @@
322 +@@ -436,15 +594,15 @@
322 323 nextticklistentry.a((long) i + this.worldData.getTime());
323 324 }
324 325
325 326 - if (!this.nextTickListHash.contains(nextticklistentry)) {
326 327 - this.nextTickListHash.add(nextticklistentry);
327 328 + // CraftBukkit - use nextTickList
328 329 + if (!this.nextTickList.contains(nextticklistentry)) {
329 330 this.nextTickList.add(nextticklistentry);
330 331 }
331 332
332 333 }
333 334
334 335 public void tickEntities() {
335 336 - if (this.players.isEmpty()) {
336 337 + if (false && this.players.isEmpty()) { // CraftBukkit - this prevents entity cleanup, other issues on servers with no players
337 338 if (this.emptyTime++ >= 300) {
338 339 return;
339 340 }
340 -@@ -514,11 +671,17 @@
341 +@@ -514,11 +672,17 @@
341 342 } else {
342 343 int i = this.nextTickList.size();
343 344
344 345 - if (i != this.nextTickListHash.size()) {
345 346 + if (false) { // CraftBukkit
346 347 throw new IllegalStateException("TickNextTick list out of synch");
347 348 } else {
348 349 if (i > 65536) {
349 350 - i = 65536;
350 351 + // CraftBukkit start - If the server has too much to process over time, try to alleviate that
351 352 + if (i > 20 * 65536) {
352 353 + i = i / 20;
353 354 + } else {
354 355 + i = 65536;
355 356 + }
356 357 + // CraftBukkit end
357 358 }
358 359
359 360 this.methodProfiler.a("cleaning");
360 -@@ -531,8 +694,9 @@
361 +@@ -531,8 +695,9 @@
361 362 break;
362 363 }
363 364
364 365 + // CraftBukkit - use nextTickList
365 366 this.nextTickList.remove(nextticklistentry);
366 367 - this.nextTickListHash.remove(nextticklistentry);
367 368 + // this.nextTickListHash.remove(nextticklistentry);
368 369 this.U.add(nextticklistentry);
369 370 }
370 371
371 -@@ -602,7 +766,7 @@
372 +@@ -602,7 +767,7 @@
372 373 if (blockposition.getX() >= structureboundingbox.a && blockposition.getX() < structureboundingbox.d && blockposition.getZ() >= structureboundingbox.c && blockposition.getZ() < structureboundingbox.f) {
373 374 if (flag) {
374 375 if (i == 0) {
375 376 - this.nextTickListHash.remove(nextticklistentry);
376 377 + // this.nextTickListHash.remove(nextticklistentry); // CraftBukkit - removed
377 378 }
378 379
379 380 iterator.remove();
380 -@@ -620,6 +784,7 @@
381 +@@ -620,6 +785,7 @@
381 382 return arraylist;
382 383 }
383 384
384 385 + /* CraftBukkit start - We prevent spawning in general, so this butchering is not needed
385 386 public void entityJoinedWorld(Entity entity, boolean flag) {
386 387 if (!this.getSpawnAnimals() && (entity instanceof EntityAnimal || entity instanceof EntityWaterAnimal)) {
387 388 entity.die();
388 -@@ -631,6 +796,7 @@
389 +@@ -631,6 +797,7 @@
389 390
390 391 super.entityJoinedWorld(entity, flag);
391 392 }
392 393 + // CraftBukkit end */
393 394
394 395 private boolean getSpawnNPCs() {
395 396 return this.server.getSpawnNPCs();
396 -@@ -643,7 +809,54 @@
397 +@@ -643,7 +810,54 @@
397 398 protected IChunkProvider n() {
398 399 IChunkLoader ichunkloader = this.dataManager.createChunkLoader(this.worldProvider);
399 400
400 401 - return new ChunkProviderServer(this, ichunkloader, this.worldProvider.getChunkGenerator());
401 402 + // CraftBukkit start
402 403 + org.bukkit.craftbukkit.generator.InternalChunkGenerator gen;
403 404 +
404 405 + if (this.generator != null) {
405 406 + gen = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, this.getSeed(), this.generator);
406 407 + } else if (this.worldProvider instanceof WorldProviderHell) {
442 443 + arraylist.add(tileentity);
443 444 + }
444 445 + }
445 446 + */
446 447 + // CraftBukkit end
447 448 +
448 449 + return arraylist;
449 450 }
450 451
451 452 public boolean a(EntityHuman entityhuman, BlockPosition blockposition) {
452 -@@ -705,6 +918,23 @@
453 +@@ -705,6 +919,23 @@
453 454 int j = this.worldProvider.getSeaLevel();
454 455 int k = 8;
455 456
456 457 + // CraftBukkit start
457 458 + if (this.generator != null) {
458 459 + Random rand = new Random(this.getSeed());
459 460 + org.bukkit.Location spawn = this.generator.getFixedSpawnLocation(((WorldServer) this).getWorld(), rand);
460 461 +
461 462 + if (spawn != null) {
462 463 + if (spawn.getWorld() != ((WorldServer) this).getWorld()) {
466 467 + this.isLoading = false;
467 468 + return;
468 469 + }
469 470 + }
470 471 + }
471 472 + // CraftBukkit end
472 473 +
473 474 if (blockposition != null) {
474 475 i = blockposition.getX();
475 476 k = blockposition.getZ();
476 -@@ -714,7 +944,7 @@
477 +@@ -714,7 +945,7 @@
477 478
478 479 int l = 0;
479 480
480 481 - while (!this.worldProvider.canSpawn(i, k)) {
481 482 + while (!this.canSpawn(i, k)) { // CraftBukkit - use our own canSpawn
482 483 i += random.nextInt(64) - random.nextInt(64);
483 484 k += random.nextInt(64) - random.nextInt(64);
484 485 ++l;
485 -@@ -755,6 +985,7 @@
486 +@@ -755,6 +986,7 @@
486 487 ChunkProviderServer chunkproviderserver = this.getChunkProviderServer();
487 488
488 489 if (chunkproviderserver.e()) {
489 490 + org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit
490 491 if (iprogressupdate != null) {
491 492 iprogressupdate.a("Saving level");
492 493 }
493 -@@ -765,7 +996,8 @@
494 +@@ -765,7 +997,8 @@
494 495 }
495 496
496 497 chunkproviderserver.a(flag);
497 498 - ArrayList arraylist = Lists.newArrayList(chunkproviderserver.a());
498 499 + // CraftBukkit - ArrayList -> Collection
499 500 + Collection arraylist = chunkproviderserver.a();
500 501 Iterator iterator = arraylist.iterator();
501 502
502 503 while (iterator.hasNext()) {
503 -@@ -800,6 +1032,12 @@
504 +@@ -800,6 +1033,12 @@
504 505 }
505 506 }
506 507
507 508 + // CraftBukkit start - Save secondary data for nether/end
508 509 + if (this instanceof SecondaryWorldServer) {
509 510 + ((SecondaryWorldServer) this).c();
510 511 + }
511 512 + // CraftBukkit end
512 513 +
513 514 this.worldData.a(this.getWorldBorder().getSize());
514 515 this.worldData.d(this.getWorldBorder().getCenterX());
515 516 this.worldData.c(this.getWorldBorder().getCenterZ());
516 -@@ -834,7 +1072,7 @@
517 +@@ -813,9 +1052,13 @@
518 + this.worldMaps.a();
519 + }
520 +
521 +- public boolean addEntity(Entity entity) {
522 +- return this.i(entity) ? super.addEntity(entity) : false;
523 ++ // CraftBukkit start
524 ++ public boolean addEntity(Entity entity, SpawnReason spawnReason) { // Changed signature, added SpawnReason
525 ++ // World.addEntity(Entity) will call this, and we still want to perform
526 ++ // existing entity checking when it's called with a SpawnReason
527 ++ return this.i(entity) ? super.addEntity(entity, spawnReason) : false;
528 + }
529 ++ // CraftBukkit end
530 +
531 + public void a(Collection<Entity> collection) {
532 + ArrayList arraylist = Lists.newArrayList(collection);
533 +@@ -834,7 +1077,7 @@
517 534
518 535 private boolean i(Entity entity) {
519 536 if (entity.dead) {
520 537 - WorldServer.a.warn("Tried to add entity {} but it was marked as removed already", new Object[] { EntityTypes.b(entity)});
521 538 + // WorldServer.a.warn("Tried to add entity {} but it was marked as removed already", new Object[] { EntityTypes.b(entity)}); // CraftBukkit
522 539 return false;
523 540 } else {
524 541 UUID uuid = entity.getUniqueID();
525 -@@ -846,7 +1084,7 @@
542 +@@ -846,7 +1089,7 @@
526 543 this.f.remove(entity1);
527 544 } else {
528 545 if (!(entity instanceof EntityHuman)) {
529 546 - WorldServer.a.warn("Keeping entity {} that already exists with UUID {}", new Object[] { EntityTypes.b(entity1), uuid.toString()});
530 547 + // WorldServer.a.warn("Keeping entity {} that already exists with UUID {}", new Object[] { EntityTypes.b(entity1), uuid.toString()}); // CraftBukkit
531 548 return false;
532 549 }
533 550
534 -@@ -899,8 +1137,16 @@
551 +@@ -899,8 +1142,16 @@
535 552 }
536 553
537 554 public boolean strikeLightning(Entity entity) {
538 555 + // CraftBukkit start
539 556 + LightningStrikeEvent lightning = new LightningStrikeEvent(this.getWorld(), (org.bukkit.entity.LightningStrike) entity.getBukkitEntity());
540 557 + this.getServer().getPluginManager().callEvent(lightning);
541 558 +
542 559 + if (lightning.isCancelled()) {
543 560 + return false;
544 561 + }
545 562 + // CraftBukkit end
546 563 if (super.strikeLightning(entity)) {
547 564 - this.server.getPlayerList().sendPacketNearby((EntityHuman) null, entity.locX, entity.locY, entity.locZ, 512.0D, this.worldProvider.getDimensionManager().getDimensionID(), new PacketPlayOutSpawnEntityWeather(entity));
548 565 + this.server.getPlayerList().sendPacketNearby((EntityHuman) null, entity.locX, entity.locY, entity.locZ, 512.0D, dimension, new PacketPlayOutSpawnEntityWeather(entity)); // CraftBukkit - Use dimension
549 566 return true;
550 567 } else {
551 568 return false;
552 -@@ -916,10 +1162,20 @@
569 +@@ -916,10 +1167,20 @@
553 570 }
554 571
555 572 public Explosion createExplosion(@Nullable Entity entity, double d0, double d1, double d2, float f, boolean flag, boolean flag1) {
556 573 + // CraftBukkit start
557 574 + Explosion explosion = super.createExplosion(entity, d0, d1, d2, f, flag, flag1);
558 575 +
559 576 + if (explosion.wasCanceled) {
560 577 + return explosion;
561 578 + }
562 579 +
563 580 + /* Remove
564 581 Explosion explosion = new Explosion(this, entity, d0, d1, d2, f, flag, flag1);
565 582
566 583 explosion.a();
567 584 explosion.a(false);
568 585 + */
569 586 + // CraftBukkit end - TODO: Check if explosions are still properly implemented
570 587 if (!flag1) {
571 588 explosion.clearBlocks();
572 589 }
573 -@@ -965,7 +1221,8 @@
590 +@@ -965,7 +1226,8 @@
574 591 BlockActionData blockactiondata = (BlockActionData) iterator.next();
575 592
576 593 if (this.a(blockactiondata)) {
577 594 - 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()));
578 595 + // CraftBukkit - this.worldProvider.dimension -> this.dimension
579 596 + 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()));
580 597 }
581 598 }
582 599
583 -@@ -988,6 +1245,7 @@
600 +@@ -988,6 +1250,7 @@
584 601 boolean flag = this.W();
585 602
586 603 super.t();
587 604 + /* CraftBukkit start
588 605 if (this.n != this.o) {
589 606 this.server.getPlayerList().a((Packet) (new PacketPlayOutGameStateChange(7, this.o)), this.worldProvider.getDimensionManager().getDimensionID());
590 607 }
591 -@@ -1006,6 +1264,21 @@
608 +@@ -1006,6 +1269,21 @@
592 609 this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(7, this.o));
593 610 this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(8, this.q));
594 611 }
595 612 + // */
596 613 + if (flag != this.W()) {
597 614 + // Only send weather packets to those affected
598 615 + for (int i = 0; i < this.players.size(); ++i) {
599 616 + if (((EntityPlayer) this.players.get(i)).world == this) {
600 617 + ((EntityPlayer) this.players.get(i)).setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false);
601 618 + }
602 619 + }
603 620 + }
604 621 + for (int i = 0; i < this.players.size(); ++i) {
605 622 + if (((EntityPlayer) this.players.get(i)).world == this) {
606 623 + ((EntityPlayer) this.players.get(i)).updateWeather(this.n, this.o, this.p, this.q);
607 624 + }
608 625 + }
609 626 + // CraftBukkit end
610 627
611 628 }
612 629
613 -@@ -1035,10 +1308,20 @@
630 +@@ -1035,10 +1313,20 @@
614 631 }
615 632
616 633 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) {
617 634 + // CraftBukkit - visibility api support
618 635 + sendParticles(null, enumparticle, flag, d0, d1, d2, i, d3, d4, d5, d6, aint);
619 636 + }
620 637 +
621 638 + 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) {
622 639 + // CraftBukkit end
623 640 PacketPlayOutWorldParticles packetplayoutworldparticles = new PacketPlayOutWorldParticles(enumparticle, flag, (float) d0, (float) d1, (float) d2, (float) d3, (float) d4, (float) d5, (float) d6, i, aint);

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut