Upstream Paper fully

This commit is contained in:
Sotr
2018-07-27 09:09:57 +08:00
parent 3d34b1e011
commit 4d44c9f8cc
5 changed files with 145 additions and 9 deletions

View File

@@ -1,15 +1,18 @@
package net.minecraft.server; package net.minecraft.server;
import com.destroystokyo.paper.PaperWorldConfig.DuplicateUUIDMode;
import com.destroystokyo.paper.exception.ServerInternalException; import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Queues; import com.google.common.collect.Queues;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@@ -36,6 +39,7 @@ public class Chunk {
public final World world; public final World world;
public final int[] heightMap; public final int[] heightMap;
public Long scheduledForUnload; // Paper - delay chunk unloads public Long scheduledForUnload; // Paper - delay chunk unloads
private static final Logger logger = LogManager.getLogger(); // Paper
public final int locX; public final int locX;
public final int locZ; public final int locZ;
private boolean m; private boolean m;
@@ -679,8 +683,34 @@ public class Chunk {
entity.ab = this.locX; entity.ab = this.locX;
entity.ac = k; entity.ac = k;
entity.ad = this.locZ; entity.ad = this.locZ;
this.entitySlices[k].add(entity);
// Paper start // Paper start
List<Entity> entitySlice = this.entitySlices[k];
boolean inThis = entitySlice.contains(entity);
if (entity.entitySlice != null || inThis) {
if (entity.entitySlice == entitySlice || inThis) {
LogManager.getLogger().warn(entity + " was already in this chunk section! Report this to https://github.com/PaperMC/Paper/issues/1223");
new Throwable().printStackTrace();
return;
} else {
LogManager.getLogger().warn(entity + " is still in another ChunkSection! Report this to https://github.com/PaperMC/Paper/issues/1223");
Chunk chunk = entity.getCurrentChunk();
if (chunk != null) {
if (chunk != this) {
LogManager.getLogger().warn(entity + " was in another chunk at that! " + chunk.locX + "," + chunk.locZ);
}
chunk.removeEntity(entity);
} else {
removeEntity(entity);
}
new Throwable().printStackTrace();
}
}
entity.entitySlice = entitySlice;
entitySlice.add(entity);
this.markDirty();
entity.setCurrentChunk(this); entity.setCurrentChunk(this);
entityCounts.increment(entity.entityKeyString); entityCounts.increment(entity.entityKeyString);
if (entity instanceof EntityItem) { if (entity instanceof EntityItem) {
@@ -723,6 +753,13 @@ public class Chunk {
// Paper start // Paper start
if (!this.entitySlices[i].remove(entity)) { return; } if (!this.entitySlices[i].remove(entity)) { return; }
if (entitySlices[i] == entity.entitySlice) {
entity.entitySlice = null;
} else {
LogManager.getLogger().warn(entity + " was removed from a entitySlice we did not expect. Report this to https://github.com/PaperMC/Paper/issues/1223");
new Throwable().printStackTrace();
}
this.markDirty();
entity.setCurrentChunk(null); entity.setCurrentChunk(null);
entityCounts.decrement(entity.entityKeyString); entityCounts.decrement(entity.entityKeyString);
if (entity instanceof EntityItem) { if (entity instanceof EntityItem) {
@@ -856,6 +893,36 @@ public class Chunk {
for (int j = 0; j < i; ++j) { for (int j = 0; j < i; ++j) {
List entityslice = aentityslice[j]; // Spigot List entityslice = aentityslice[j]; // Spigot
// Paper start
DuplicateUUIDMode mode = world.paperConfig.duplicateUUIDMode;
if (mode == DuplicateUUIDMode.DELETE || mode == DuplicateUUIDMode.REGEN) {
Map<UUID, Entity> thisChunk = new HashMap<>();
for (Iterator<Entity> iterator = ((List<Entity>) entityslice).iterator(); iterator.hasNext(); ) {
Entity entity = iterator.next();
if (entity.dead) continue;
Entity other = ((WorldServer) world).entitiesByUUID.get(entity.uniqueID);
if (other == null) {
other = thisChunk.get(entity.uniqueID);
}
if (other != null && !other.dead) {
switch (mode) {
case REGEN: {
entity.setUUID(UUID.randomUUID());
logger.warn("[DUPE-UUID] Duplicate UUID found used by " + other + ", regenerated UUID for " + entity + ". See https://github.com/PaperMC/Paper/issues/1223 for discussion on what this is about.");
break;
}
case DELETE: {
logger.warn("[DUPE-UUID] Duplicate UUID found used by " + other + ", deleted entity " + entity + ". See https://github.com/PaperMC/Paper/issues/1223 for discussion on what this is about.");
entity.die();
iterator.remove();
break;
}
}
}
thisChunk.put(entity.uniqueID, entity);
}
}
// Paper end
this.world.a((Collection) entityslice); this.world.a((Collection) entityslice);
} }

View File

@@ -50,7 +50,21 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
// CraftBukkit start // CraftBukkit start
private static final int CURRENT_LEVEL = 2; private static final int CURRENT_LEVEL = 2;
public static Random SHARED_RANDOM = new io.akarin.api.internal.utils.random.LightRandom(); // Paper // Akarin - LightRNG // Paper start
public static Random SHARED_RANDOM = new io.akarin.api.internal.utils.random.LightRandom() { // Akarin - LightRNG
private boolean locked = false;
@Override
public synchronized void setSeed(long seed) {
if (locked) {
LogManager.getLogger().error("Ignoring setSeed on Entity.SHARED_RANDOM", new Throwable());
} else {
super.setSeed(seed);
locked = true;
}
}
};
Object entitySlice = null;
// Paper end
static boolean isLevelAtLeast(NBTTagCompound tag, int level) { static boolean isLevelAtLeast(NBTTagCompound tag, int level) {
return tag.hasKey("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level; return tag.hasKey("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level;
} }
@@ -64,6 +78,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
} }
return bukkitEntity; return bukkitEntity;
} }
Throwable addedToWorldStack; // Paper - entity debug
// CraftBukikt end // CraftBukikt end
private static final Logger a = LogManager.getLogger(); private static final Logger a = LogManager.getLogger();
@@ -2352,7 +2367,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
} }
public String toString() { public String toString() {
return String.format("%s[\'%s\'/%d, uuid=\'%s\', l=\'%s\', x=%.2f, y=%.2f, z=%.2f]", new Object[] { this.getClass().getSimpleName(), this.getName(), Integer.valueOf(this.id), this.uniqueID.toString(), this.world == null ? "~NULL~" : this.world.getWorldData().getName(), Double.valueOf(this.locX), Double.valueOf(this.locY), Double.valueOf(this.locZ)}); // Paper - add UUID return String.format("%s[\'%s\'/%d, uuid=\'%s\', l=\'%s\', x=%.2f, y=%.2f, z=%.2f, cx=%d, cd=%d, tl=%d, v=%b, d=%b]", new Object[] { this.getClass().getSimpleName(), this.getName(), Integer.valueOf(this.id), this.uniqueID.toString(), this.world == null ? "~NULL~" : this.world.getWorldData().getName(), Double.valueOf(this.locX), Double.valueOf(this.locY), Double.valueOf(this.locZ), getChunkX(), getChunkZ(), this.ticksLived, this.valid, this.dead}); // Paper - add more information
} }
public boolean isInvulnerable(DamageSource damagesource) { public boolean isInvulnerable(DamageSource damagesource) {
@@ -2604,6 +2619,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
}); });
} }
public void setUUID(UUID uuid) { a(uuid); } // Paper - OBFHELPER
public void a(UUID uuid) { public void a(UUID uuid) {
this.uniqueID = uuid; this.uniqueID = uuid;
this.ar = this.uniqueID.toString(); this.ar = this.uniqueID.toString();

View File

@@ -6,6 +6,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -40,7 +41,7 @@ public class WorldServer extends World implements IAsyncTaskHandler {
public final PlayerChunkMap manager; // Akarin - private -> public public final PlayerChunkMap manager; // Akarin - private -> public
// private final Set<NextTickListEntry> nextTickListHash = Sets.newHashSet(); // private final Set<NextTickListEntry> nextTickListHash = Sets.newHashSet();
private final HashTreeSet<NextTickListEntry> nextTickList = new HashTreeSet<NextTickListEntry>(); // CraftBukkit - HashTreeSet private final HashTreeSet<NextTickListEntry> nextTickList = new HashTreeSet<NextTickListEntry>(); // CraftBukkit - HashTreeSet
private final Map<UUID, Entity> entitiesByUUID = Maps.newHashMap(); public final Map<UUID, Entity> entitiesByUUID = Maps.newHashMap(); // Paper
public boolean savingDisabled; public boolean savingDisabled;
private boolean Q; private boolean Q;
private int emptyTime; private int emptyTime;
@@ -52,6 +53,10 @@ public class WorldServer extends World implements IAsyncTaskHandler {
private final List<NextTickListEntry> W = Lists.newArrayList(); private final List<NextTickListEntry> W = Lists.newArrayList();
// CraftBukkit start // CraftBukkit start
private static final boolean DEBUG_ENTITIES = Boolean.getBoolean("debug.entities"); // Paper
private static Throwable getAddToWorldStackTrace(Entity entity) {
return new Throwable(entity + " Added to world at " + new Date());
}
public final int dimension; public final int dimension;
// Add env and gen to constructor // Add env and gen to constructor
@@ -1181,6 +1186,7 @@ public class WorldServer extends World implements IAsyncTaskHandler {
private boolean j(Entity entity) { private boolean j(Entity entity) {
if (entity.dead) { if (entity.dead) {
WorldServer.a.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.a(entity)); // CraftBukkit // Paper WorldServer.a.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.a(entity)); // CraftBukkit // Paper
if (DEBUG_ENTITIES) getAddToWorldStackTrace(entity).printStackTrace();
return false; return false;
} else { } else {
UUID uuid = entity.getUniqueID(); UUID uuid = entity.getUniqueID();
@@ -1188,12 +1194,21 @@ public class WorldServer extends World implements IAsyncTaskHandler {
if (this.entitiesByUUID.containsKey(uuid)) { if (this.entitiesByUUID.containsKey(uuid)) {
Entity entity1 = this.entitiesByUUID.get(uuid); Entity entity1 = this.entitiesByUUID.get(uuid);
if (this.f.contains(entity1)) { if (this.f.contains(entity1) || entity1.dead) { // Paper - overwrite the current dead one
this.f.remove(entity1); this.f.remove(entity1);
} else { } else {
if (!(entity instanceof EntityHuman)) { if (!(entity instanceof EntityHuman)) {
WorldServer.a.error("Keeping entity {} that already exists with UUID {} - " + entity1, EntityTypes.a(entity1), uuid.toString()); // CraftBukkit // Paper if (entity.world.paperConfig.duplicateUUIDMode != com.destroystokyo.paper.PaperWorldConfig.DuplicateUUIDMode.NOTHING) {
WorldServer.a.error("Deleting duplicate entity {}", entity); // Paper WorldServer.a.error("Keeping entity {} that already exists with UUID {}", entity1, uuid.toString()); // CraftBukkit // Paper
WorldServer.a.error("Duplicate entity {} will not be added to the world. See paper.yml duplicate-uuid-resolver and set this to either regen, delete or nothing to get rid of this message", entity); // Paper
if (DEBUG_ENTITIES) {
if (entity1.addedToWorldStack != null) {
entity1.addedToWorldStack.printStackTrace();
}
getAddToWorldStackTrace(entity).printStackTrace();
}
}
return false; return false;
} }
@@ -1211,7 +1226,24 @@ public class WorldServer extends World implements IAsyncTaskHandler {
protected void b(Entity entity) { protected void b(Entity entity) {
super.b(entity); super.b(entity);
this.entitiesById.a(entity.getId(), entity); this.entitiesById.a(entity.getId(), entity);
this.entitiesByUUID.put(entity.getUniqueID(), entity); // Paper start
if (DEBUG_ENTITIES) {
entity.addedToWorldStack = getAddToWorldStackTrace(entity);
}
Entity old = this.entitiesByUUID.put(entity.getUniqueID(), entity);
if (old != null && old.getId() != entity.getId() && old.valid && entity.world.paperConfig.duplicateUUIDMode != com.destroystokyo.paper.PaperWorldConfig.DuplicateUUIDMode.NOTHING) {
Logger logger = LogManager.getLogger();
logger.error("Overwrote an existing entity " + old + " with " + entity);
if (DEBUG_ENTITIES) {
if (old.addedToWorldStack != null) {
old.addedToWorldStack.printStackTrace();
} else {
logger.error("Oddly, the old entity was not added to the world in the normal way. Plugins?");
}
entity.addedToWorldStack.printStackTrace();
}
}
// Paper end
Entity[] aentity = entity.bb(); Entity[] aentity = entity.bb();
if (aentity != null) { if (aentity != null) {

View File

@@ -1179,11 +1179,32 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
for (EntityPlayer player : players) { for (EntityPlayer player : players) {
player.getBukkitEntity().reregisterPlayer(self); player.getBukkitEntity().reregisterPlayer(self);
} }
refreshPlayer();
} }
@Override @Override
public PlayerProfile getPlayerProfile() { public PlayerProfile getPlayerProfile() {
return new CraftPlayerProfile(this).clone(); return new CraftPlayerProfile(this).clone();
} }
private void refreshPlayer() {
EntityPlayer handle = getHandle();
Location loc = getLocation();
PlayerConnection connection = handle.playerConnection;
reregisterPlayer(handle);
//Respawn the player then update their position and selected slot
connection.sendPacket(new PacketPlayOutRespawn(handle.dimension, handle.world.getDifficulty(), handle.world.getWorldData().getType(), handle.playerInteractManager.getGameMode()));
handle.updateAbilities();
connection.sendPacket(new PacketPlayOutPosition(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch(), new HashSet<>(), 0));
MinecraftServer.getServer().getPlayerList().updateClient(handle);
if (this.isOp()) {
this.setOp(false);
this.setOp(true);
}
}
// Paper end // Paper end
public void removeDisconnectingPlayer(Player player) { public void removeDisconnectingPlayer(Player player) {