Fire PlayerJoinEvent when Player is actually ready

For years, plugin developers have had to delay many things they do
inside of the PlayerJoinEvent by 1 tick to make it actually work.

This all boiled down to 1 reason why: The event fired before the
player was fully ready and joined to the world!

Additionally, if that player logged out on a vehicle, the event
fired before the vehicle was even loaded, so that plugins had no
access to the vehicle during this event either.

This change finally fixes this issue, fully preparing the player
into the world as a fully ready entity, vehicle included.

There should be no plugins that break because of this change, but might
improve consistency with other plugins instead.

For example, if 2 plugins listens to this event, and the first one
teleported the player in the event, then the 2nd plugin actually
would be getting a valid player!

This was very non deterministic. This change will ensure every plugin
receives a deterministic result, and should no longer require 1 tick
delays anymore.

== AT ==
public net.minecraft.server.level.ChunkMap addEntity(Lnet/minecraft/world/entity/Entity;)V
This commit is contained in:
Aikar
2020-04-19 00:05:46 -04:00
parent b7898433d0
commit d7f24e6729
3 changed files with 122 additions and 110 deletions

View File

@@ -320,7 +320,7 @@
}
}
@@ -1215,9 +1291,18 @@
@@ -1215,9 +1291,19 @@
}
public void addEntity(Entity entity) {
@@ -332,6 +332,7 @@
+ return;
+ }
+ // Paper end - ignore and warn about illegal addEntity calls instead of crashing server
+ if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Paper - Fire PlayerJoinEvent when Player is actually ready; Delay adding to tracker until after list packets
if (!(entity instanceof EnderDragonPart)) {
EntityType<?> entitytypes = entity.getType();
int i = entitytypes.clientTrackingRange() * 16;
@@ -339,7 +340,7 @@
if (i != 0) {
int j = entitytypes.updateInterval();
@@ -1250,6 +1335,7 @@
@@ -1250,6 +1336,7 @@
}
protected void removeEntity(Entity entity) {
@@ -347,7 +348,7 @@
if (entity instanceof ServerPlayer entityplayer) {
this.updatePlayerStatus(entityplayer, false);
ObjectIterator objectiterator = this.entityMap.values().iterator();
@@ -1391,7 +1477,7 @@
@@ -1391,7 +1478,7 @@
});
}
@@ -356,7 +357,7 @@
protected ChunkDistanceManager(final Executor workerExecutor, final Executor mainThreadExecutor) {
super(workerExecutor, mainThreadExecutor);
@@ -1424,7 +1510,7 @@
@@ -1424,7 +1511,7 @@
public final Set<ServerPlayerConnection> seenBy = Sets.newIdentityHashSet();
public TrackedEntity(final Entity entity, final int i, final int j, final boolean flag) {
@@ -365,7 +366,7 @@
this.entity = entity;
this.range = i;
this.lastSectionPos = SectionPos.of((EntityAccess) entity);
@@ -1469,6 +1555,7 @@
@@ -1469,6 +1556,7 @@
}
public void removePlayer(ServerPlayer player) {
@@ -373,7 +374,7 @@
if (this.seenBy.remove(player.connection)) {
this.serverEntity.removePairing(player);
}
@@ -1476,6 +1563,7 @@
@@ -1476,6 +1564,7 @@
}
public void updatePlayer(ServerPlayer player) {
@@ -381,7 +382,7 @@
if (player != this.entity) {
Vec3 vec3d = player.position().subtract(this.entity.position());
int i = ChunkMap.this.getPlayerViewDistance(player);
@@ -1484,6 +1572,11 @@
@@ -1484,6 +1573,11 @@
double d2 = d0 * d0;
boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z);
@@ -393,7 +394,7 @@
if (flag) {
if (this.seenBy.add(player.connection)) {
this.serverEntity.addPairing(player);
@@ -1506,6 +1599,7 @@
@@ -1506,6 +1600,7 @@
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
int j = entity.getType().clientTrackingRange() * 16;