Mirror von
https://github.com/PaperMC/Paper.git
synchronisiert 2024-12-19 04:50:06 +01:00
Handle removing entity while ticking. Fixes BUKKIT-1331
If a plugin causes an entity to be removed from the world while the world is ticking entities the ticking loop gets out of sync and fails due to trying to go beyond the end of the entity array. To ensure this doesn't happen we store the loop position as a field so we can fix it up in the entity remove method just like the tick method does when it removes an entity.
Dieser Commit ist enthalten in:
Ursprung
1113d54dae
Commit
826643c606
@ -14,7 +14,6 @@ import java.util.concurrent.Callable;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
|
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
|
||||||
import org.bukkit.craftbukkit.util.LongHashSet;
|
import org.bukkit.craftbukkit.util.LongHashSet;
|
||||||
import org.bukkit.craftbukkit.util.UnsafeList;
|
|
||||||
import org.bukkit.generator.ChunkGenerator;
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
import org.bukkit.craftbukkit.CraftServer;
|
import org.bukkit.craftbukkit.CraftServer;
|
||||||
import org.bukkit.craftbukkit.CraftWorld;
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
@ -71,6 +70,7 @@ public abstract class World implements IBlockAccess {
|
|||||||
public long ticksPerAnimalSpawns;
|
public long ticksPerAnimalSpawns;
|
||||||
public long ticksPerMonsterSpawns;
|
public long ticksPerMonsterSpawns;
|
||||||
public boolean populating;
|
public boolean populating;
|
||||||
|
private int tickPosition;
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
private ArrayList M;
|
private ArrayList M;
|
||||||
private boolean N;
|
private boolean N;
|
||||||
@ -974,7 +974,14 @@ public abstract class World implements IBlockAccess {
|
|||||||
this.getChunkAt(i, j).b(entity);
|
this.getChunkAt(i, j).b(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.entityList.remove(entity);
|
// CraftBukkit start - Decrement loop variable field if we've already ticked this entity
|
||||||
|
int index = this.entityList.indexOf(entity);
|
||||||
|
if (index <= this.tickPosition) {
|
||||||
|
this.tickPosition--;
|
||||||
|
}
|
||||||
|
this.entityList.remove(index);
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
this.b(entity);
|
this.b(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1182,10 +1189,11 @@ public abstract class World implements IBlockAccess {
|
|||||||
this.f.clear();
|
this.f.clear();
|
||||||
this.methodProfiler.c("regular");
|
this.methodProfiler.c("regular");
|
||||||
|
|
||||||
for (i = 0; i < this.entityList.size(); ++i) {
|
// CraftBukkit start - Use field for loop variable
|
||||||
entity = (Entity) this.entityList.get(i);
|
for (this.tickPosition = 0; this.tickPosition < this.entityList.size(); ++this.tickPosition) {
|
||||||
|
entity = (Entity) this.entityList.get(this.tickPosition);
|
||||||
|
|
||||||
// CraftBukkit start - Don't tick entities in chunks queued for unload
|
// Don't tick entities in chunks queued for unload
|
||||||
ChunkProviderServer chunkProviderServer = ((WorldServer) this).chunkProviderServer;
|
ChunkProviderServer chunkProviderServer = ((WorldServer) this).chunkProviderServer;
|
||||||
if (chunkProviderServer.unloadQueue.contains(MathHelper.floor(entity.locX) >> 4, MathHelper.floor(entity.locZ) >> 4)) {
|
if (chunkProviderServer.unloadQueue.contains(MathHelper.floor(entity.locX) >> 4, MathHelper.floor(entity.locZ) >> 4)) {
|
||||||
continue;
|
continue;
|
||||||
@ -1222,7 +1230,7 @@ public abstract class World implements IBlockAccess {
|
|||||||
this.getChunkAt(j, k).b(entity);
|
this.getChunkAt(j, k).b(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.entityList.remove(i--);
|
this.entityList.remove(this.tickPosition--); // CraftBukkit - Use field for loop variable
|
||||||
this.b(entity);
|
this.b(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren