more patches (#5811)

This commit is contained in:
Jake Potrebic 2021-06-12 16:45:00 -07:00 committed by GitHub
parent 0c2d1544ac
commit 2ba2c29b2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 711 additions and 1074 deletions

View file

@ -0,0 +1,28 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 23 Jul 2018 22:18:31 -0400
Subject: [PATCH] Mark chunk dirty anytime entities change to guarantee it
saves
Useless in 1.17 - leaf
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index d69ccb1f31f31ebeee477df20ce1410f9e485eb7..bd9b19d988ecf72e099efeff6ec3483a352174ec 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -559,6 +559,7 @@ public class LevelChunk implements ChunkAccess {
entity.zChunk = this.chunkPos.z;
this.entities.add(entity); // Paper - per chunk entity list
this.entitySlices[k].add(entity);
+ this.markUnsaved(); // Paper
}
@Override
@@ -587,6 +588,7 @@ public class LevelChunk implements ChunkAccess {
return;
}
entityCounts.decrement(entity.getMinecraftKeyString());
+ this.markUnsaved(); // Paper
// Paper end
this.entities.remove(entity); // Paper
}

View file

@ -0,0 +1,101 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 23 Jul 2018 22:44:23 -0400
Subject: [PATCH] Add some Debug to Chunk Entity slices
If we detect unexpected state, log and try to recover
This should hopefully avoid duplicate entities ever being created
if the entity was to end up in 2 different chunk slices
Useless in 1.17
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index a2cc3e58d59ed3d9f443b77c44d8200cc09b4da9..7847078c54154e28ab066ea8a329f929df1e1a37 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -156,6 +156,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
}
}
};
+ public List<Entity> entitySlice = null;
// Paper end
public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index bd9b19d988ecf72e099efeff6ec3483a352174ec..09aa608bd303b618ae2c0ebd237bcbdba60a37a8 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -26,7 +26,9 @@ import net.minecraft.ReportedException;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.nbt.CompoundTag;
+import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder;
+import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
@@ -550,6 +552,25 @@ public class LevelChunk implements ChunkAccess {
if (k >= this.entitySlices.length) {
k = this.entitySlices.length - 1;
}
+ // Paper - remove from any old list if its in one
+ List<Entity> nextSlice = this.entitySlices[k]; // the next list to be added to
+ List<Entity> currentSlice = entity.entitySlice;
+ if (nextSlice == currentSlice) {
+ if (Level.DEBUG_ENTITIES) MinecraftServer.LOGGER.warn("Entity was already in this chunk!" + entity, new Throwable());
+ return; // ??? silly plugins
+ }
+ if (currentSlice != null && currentSlice.contains(entity)) {
+ // Still in an old chunk...
+ if (Level.DEBUG_ENTITIES) MinecraftServer.LOGGER.warn("Entity is still in another chunk!" + entity, new Throwable());
+ LevelChunk chunk = entity.getCurrentChunk();
+ if (chunk != null) {
+ chunk.removeEntity(entity);
+ } else {
+ removeEntity(entity);
+ }
+ currentSlice.remove(entity); // Just incase the above did not remove from the previous slice
+ }
+ // Paper end
if (!entity.inChunk || entity.getCurrentChunk() != this) entityCounts.increment(entity.getMinecraftKeyString()); // Paper
entity.inChunk = true;
@@ -559,6 +580,7 @@ public class LevelChunk implements ChunkAccess {
entity.zChunk = this.chunkPos.z;
this.entities.add(entity); // Paper - per chunk entity list
this.entitySlices[k].add(entity);
+ entity.entitySlice = this.entitySlices[k]; // Paper
this.markUnsaved(); // Paper
}
@@ -584,6 +606,10 @@ public class LevelChunk implements ChunkAccess {
// Paper start
if (entity.currentChunk != null && entity.currentChunk.get() == this) entity.setCurrentChunk(null);
+ if (entitySlices[section] == entity.entitySlice) {
+ entity.entitySlice = null;
+ entity.inChunk = false;
+ }
if (!this.entitySlices[section].remove(entity)) {
return;
}
@@ -742,7 +768,7 @@ public class LevelChunk implements ChunkAccess {
// Paper start - neighbour cache
int chunkX = this.chunkPos.x;
int chunkZ = this.chunkPos.z;
- ChunkProviderServer chunkProvider = ((ServerLevel)this.world).getChunkSource();
+ ServerChunkCache chunkProvider = ((ServerLevel)this.world).getChunkSource();
for (int dx = -NEIGHBOUR_CACHE_RADIUS; dx <= NEIGHBOUR_CACHE_RADIUS; ++dx) {
for (int dz = -NEIGHBOUR_CACHE_RADIUS; dz <= NEIGHBOUR_CACHE_RADIUS; ++dz) {
LevelChunk neighbour = chunkProvider.getChunkAtIfLoadedMainThreadNoCache(chunkX + dx, chunkZ + dz);
@@ -802,7 +828,7 @@ public class LevelChunk implements ChunkAccess {
// Paper start - neighbour cache
int chunkX = this.chunkPos.x;
int chunkZ = this.chunkPos.z;
- ChunkProviderServer chunkProvider = ((ServerLevel)this.world).getChunkSource();
+ ServerChunkCache chunkProvider = ((ServerLevel)this.world).getChunkSource();
for (int dx = -NEIGHBOUR_CACHE_RADIUS; dx <= NEIGHBOUR_CACHE_RADIUS; ++dx) {
for (int dz = -NEIGHBOUR_CACHE_RADIUS; dz <= NEIGHBOUR_CACHE_RADIUS; ++dz) {
LevelChunk neighbour = chunkProvider.getChunkAtIfLoadedMainThreadNoCache(chunkX + dx, chunkZ + dz);

View file

@ -0,0 +1,129 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 26 Jul 2018 00:11:12 -0400
Subject: [PATCH] Prevent Saving Bad entities to chunks
See https://github.com/PaperMC/Paper/issues/1223
Minecraft is saving invalid entities to the chunk files.
Avoid saving bad data, and also make improvements to handle
loading these chunks. Any invalid entity will be instant killed,
so lets avoid adding it to the world...
This lets us be safer about the dupe UUID resolver too, as now
we can ignore instant killed entities and avoid risk of duplicating
an invalid entity.
This should reduce log occurrences of dupe uuid messages.
1.17, not a concern anymore
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index a5d7781b13a6d61238d026f064512f7162e1e868..8e8e5f30c512ed7d8ee987550c22d3e9df845043 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1151,6 +1151,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
List[] aentityslice = chunk.getEntitySlices(); // Spigot
int i = aentityslice.length;
+ java.util.List<Entity> toMoveChunks = new java.util.ArrayList<>(); // Paper
for (int j = 0; j < i; ++j) {
List<Entity> entityslice = aentityslice[j]; // Spigot
Iterator iterator = entityslice.iterator();
@@ -1163,11 +1164,25 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
throw (IllegalStateException) Util.pauseInIde((Throwable) (new IllegalStateException("Removing entity while ticking!")));
}
+ // Paper start - move out entities that shouldn't be in this chunk before it unloads
+ if (!entity.removed && (int) Math.floor(entity.getX()) >> 4 != chunk.getPos().x || (int) Math.floor(entity.getZ()) >> 4 != chunk.getPos().z) {
+ toMoveChunks.add(entity);
+ continue;
+ }
+ // Paper end
+
this.entitiesById.remove(entity.getId());
this.onEntityRemoved(entity);
+
+ if (entity.removed) iterator.remove(); // Paper - don't save dead entities during unload
}
}
}
+ // Paper start - move out entities that shouldn't be in this chunk before it unloads
+ for (Entity entity : toMoveChunks) {
+ this.updateChunkPos(entity);
+ }
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
index 0efaf4d0f58bcf38b427e76bf09b96e354294159..542d6f322df5f44ad9f504c8e14c88e3fa540657 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
@@ -27,6 +27,7 @@ import net.minecraft.nbt.LongArrayTag;
import net.minecraft.nbt.ShortTag;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
@@ -349,6 +350,7 @@ public class ChunkSerializer {
nbttagcompound1.put("TileEntities", nbttaglist1);
ListTag nbttaglist2 = new ListTag();
+ java.util.List<Entity> toUpdate = new java.util.ArrayList<>(); // Paper
if (chunk.getStatus().getChunkType() == ChunkStatus.ChunkType.LEVELCHUNK) {
LevelChunk chunk1 = (LevelChunk) chunk;
@@ -366,13 +368,28 @@ public class ChunkSerializer {
while (iterator1.hasNext()) {
Entity entity = (Entity) iterator1.next();
CompoundTag nbttagcompound4 = new CompoundTag();
-
+ // Paper start
+ if ((int) Math.floor(entity.getX()) >> 4 != chunk1.getPos().x || (int) Math.floor(entity.getZ()) >> 4 != chunk1.getPos().z) {
+ toUpdate.add(entity);
+ continue;
+ }
+ if (entity.removed || hasPlayerPassenger(entity)) {
+ continue;
+ }
+ // Paper end
if (entity.save(nbttagcompound4)) {
chunk1.setLastSaveHadEntities(true);
nbttaglist2.add(nbttagcompound4);
}
}
}
+
+ // Paper start - move entities to the correct chunk
+ for (Entity entity : toUpdate) {
+ world.updateChunkPos(entity);
+ }
+ // Paper end
+
} else {
ProtoChunk protochunk = (ProtoChunk) chunk;
@@ -431,6 +448,19 @@ public class ChunkSerializer {
nbttagcompound1.put("Structures", packStructureData(chunkcoordintpair, chunk.getAllStarts(), chunk.getAllReferences()));
return nbttagcompound;
}
+ // Paper start - this is saved with the player
+ private static boolean hasPlayerPassenger(Entity entity) {
+ for (Entity passenger : entity.passengers) {
+ if (passenger instanceof ServerPlayer) {
+ return true;
+ }
+ if (hasPlayerPassenger(passenger)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ // Paper end
public static ChunkStatus.ChunkType getChunkTypeFromTag(@Nullable CompoundTag tag) {
if (tag != null) {

View file

@ -0,0 +1,122 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 28 Jul 2018 12:18:27 -0400
Subject: [PATCH] Ignore Dead Entities in entityList iteration
A spigot change delays removal of entities from the entity list.
This causes a change in behavior from Vanilla where getEntities type
methods will return dead entities that they shouldn't otherwise be doing.
This will ensure that dead entities are skipped from iteration since
they shouldn't of been in the list in the first place.
Not relevant in 1.17
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
index e95b91cefb0374bd5bb57cc090f5ecd566d7a618..8fd716bf2e1402694798b8be03fd85821153be44 100644
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
@@ -209,6 +209,7 @@ public class PaperCommand extends Command {
Collection<Entity> entities = world.entitiesById.values();
entities.forEach(e -> {
ResourceLocation key = e.getMinecraftKey();
+ if (e.shouldBeRemoved) return; // Paper
MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));
ChunkPos chunk = new ChunkPos(e.xChunk, e.zChunk);
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 8e8e5f30c512ed7d8ee987550c22d3e9df845043..84b2cd661697545186677ab7966556d9288c650b 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1303,6 +1303,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
entity.origin = entity.getBukkitEntity().getLocation();
}
// Paper end
+ entity.shouldBeRemoved = false; // Paper - shouldn't be removed after being re-added
new com.destroystokyo.paper.event.entity.EntityAddToWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
}
@@ -1315,6 +1316,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
this.removeFromChunk(entity);
this.entitiesById.remove(entity.getId());
this.onEntityRemoved(entity);
+ entity.shouldBeRemoved = true; // Paper
}
}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 7847078c54154e28ab066ea8a329f929df1e1a37..5bf6bc6a01ccde8a4d67b49293bb326cb09248d8 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -275,6 +275,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
protected int numCollisions = 0; // Paper
public void inactiveTick() { }
// Spigot end
+ public boolean shouldBeRemoved; // Paper
public float getBukkitYaw() {
return this.yRot;
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 09aa608bd303b618ae2c0ebd237bcbdba60a37a8..db28bfe95c885cdefa855c7aaa3bcf92bc52df26 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -862,6 +862,7 @@ public class LevelChunk implements ChunkAccess {
for (int i1 = 0; i1 < l; ++i1) {
Entity entity1 = (Entity) list1.get(i1);
+ if (entity1.shouldBeRemoved) continue; // Paper
if (entity1.getBoundingBox().intersects(box) && entity1 != except) {
if (predicate == null || predicate.test(entity1)) {
@@ -899,6 +900,7 @@ public class LevelChunk implements ChunkAccess {
while (iterator.hasNext()) {
T entity = (T) iterator.next(); // CraftBukkit - decompile error
+ if (entity.shouldBeRemoved) continue; // Paper
if ((type == null || entity.getType() == type) && entity.getBoundingBox().intersects(box) && predicate.test(entity)) {
result.add(entity);
@@ -921,6 +923,7 @@ public class LevelChunk implements ChunkAccess {
while (iterator.hasNext()) {
T t0 = (T) iterator.next(); // CraftBukkit - decompile error
+ if (t0.shouldBeRemoved) continue; // Paper
if (entityClass.isInstance(t0) && t0.getBoundingBox().intersects(box) && (predicate == null || predicate.test(t0))) { // Spigot - instance check
result.add(t0);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 3a3466cd9bbd34dbc0b79567f5579e84a81d6009..9807612aed6c4393cbe1f4b6078e45bf1ba3deb2 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1022,6 +1022,7 @@ public class CraftWorld implements World {
for (Object o : world.entitiesById.values()) {
if (o instanceof net.minecraft.world.entity.Entity) {
net.minecraft.world.entity.Entity mcEnt = (net.minecraft.world.entity.Entity) o;
+ if (mcEnt.shouldBeRemoved) continue; // Paper
Entity bukkitEntity = mcEnt.getBukkitEntity();
// Assuming that bukkitEntity isn't null
@@ -1041,6 +1042,7 @@ public class CraftWorld implements World {
for (Object o : world.entitiesById.values()) {
if (o instanceof net.minecraft.world.entity.Entity) {
net.minecraft.world.entity.Entity mcEnt = (net.minecraft.world.entity.Entity) o;
+ if (mcEnt.shouldBeRemoved) continue; // Paper
Entity bukkitEntity = mcEnt.getBukkitEntity();
// Assuming that bukkitEntity isn't null
@@ -1067,6 +1069,7 @@ public class CraftWorld implements World {
for (Object entity: world.entitiesById.values()) {
if (entity instanceof net.minecraft.world.entity.Entity) {
+ if (((net.minecraft.world.entity.Entity) entity).shouldBeRemoved) continue; // Paper
Entity bukkitEntity = ((net.minecraft.world.entity.Entity) entity).getBukkitEntity();
if (bukkitEntity == null) {
@@ -1090,6 +1093,7 @@ public class CraftWorld implements World {
for (Object entity: world.entitiesById.values()) {
if (entity instanceof net.minecraft.world.entity.Entity) {
+ if (((net.minecraft.world.entity.Entity) entity).shouldBeRemoved) continue; // Paper
Entity bukkitEntity = ((net.minecraft.world.entity.Entity) entity).getBukkitEntity();
if (bukkitEntity == null) {