From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar Date: Sun, 18 Mar 2018 12:29:48 -0400 Subject: [PATCH] Player.setPlayerProfile API This can be useful for changing name or skins after a player has logged in. == AT == public-f net.minecraft.world.entity.player.Player gameProfile diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index f60d754cb617df3c5ab8654eba66016c1cc04617..39af3e197502c1f262fbdd4e06dc0e3fc7537b77 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1467,7 +1467,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.internalTeleport(dest.getX(), dest.getY(), dest.getZ(), dest.getYaw(), dest.getPitch(), Collections.emptySet()); } - private void internalTeleport(double d0, double d1, double d2, float f, float f1, Set set) { + public void internalTeleport(double d0, double d1, double d2, float f, float f1, Set set) { // Paper // CraftBukkit start if (Float.isNaN(f)) { f = 0; diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java index b41aa61f80cd4ab8ddd19da397244392f9efde78..e745061f3e6a4541f44ba119106915cdb7023fc6 100644 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -295,11 +295,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, // Paper start - Add more fields to AsyncPlayerPreLoginEvent final InetAddress rawAddress = ((InetSocketAddress) this.connection.channel.remoteAddress()).getAddress(); - com.destroystokyo.paper.profile.PlayerProfile profile = org.bukkit.Bukkit.createProfile(uniqueId, playerName); + com.destroystokyo.paper.profile.PlayerProfile profile = com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitMirror(gameprofile); // Paper - setPlayerProfileAPI AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, rawAddress, uniqueId, profile, this.connection.hostname); server.getPluginManager().callEvent(asyncEvent); profile = asyncEvent.getPlayerProfile(); - profile.complete(); + profile.complete(true); // Paper - setPlayerProfileAPI gameprofile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile); playerName = gameprofile.getName(); uniqueId = gameprofile.getId(); diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java index 7552d1b9e6c286daaa6b094af0fdebc2b300272a..9f8a95c8f46a11f36ff16863922a91a8d81d0bb3 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -862,10 +862,16 @@ public abstract class PlayerList { } public void sendPlayerPermissionLevel(ServerPlayer player) { + // Paper start - avoid recalculating permissions if possible + this.sendPlayerPermissionLevel(player, true); + } + + public void sendPlayerPermissionLevel(ServerPlayer player, boolean recalculatePermissions) { + // Paper end - avoid recalculating permissions if possible GameProfile gameprofile = player.getGameProfile(); int i = this.server.getProfilePermissions(gameprofile); - this.sendPlayerPermissionLevel(player, i); + this.sendPlayerPermissionLevel(player, i, recalculatePermissions); // Paper - avoid recalculating permissions if possible } public void tick() { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java index 954825dcd011716dcd859aa285a8e3cdb6ff5464..34925d6448e0ef1d5bb4b24359f732b67aaa4230 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java @@ -82,8 +82,8 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa } @Override - public PlayerProfile getPlayerProfile() { - return new CraftPlayerProfile(this.profile); + public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() { // Paper + return new com.destroystokyo.paper.profile.CraftPlayerProfile(this.profile); // Paper } public Server getServer() { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 1444b633a2b49ce492a8a3c2a9c4befb8c7618fd..f33aee99de2007701bd593917a63e05c7fa5e349 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -236,11 +236,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player { return this.server.getPlayer(this.getUniqueId()) != null; } - @Override - public PlayerProfile getPlayerProfile() { - return new CraftPlayerProfile(this.getProfile()); - } - @Override public InetSocketAddress getAddress() { if (this.getHandle().connection == null) return null; @@ -1696,8 +1691,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { private void untrackAndHideEntity(org.bukkit.entity.Entity entity) { // Remove this entity from the hidden player's EntityTrackerEntry - ChunkMap tracker = ((ServerLevel) this.getHandle().level()).getChunkSource().chunkMap; + // Paper start Entity other = ((CraftEntity) entity).getHandle(); + unregisterEntity(other); + + server.getPluginManager().callEvent(new PlayerHideEntityEvent(this, entity)); + } + private void unregisterEntity(Entity other) { + // Paper end + ChunkMap tracker = ((ServerLevel) this.getHandle().level()).getChunkSource().chunkMap; ChunkMap.TrackedEntity entry = tracker.entityMap.get(other.getId()); if (entry != null) { entry.removePlayer(this.getHandle()); @@ -1710,8 +1712,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player { this.getHandle().connection.send(new ClientboundPlayerInfoRemovePacket(List.of(otherPlayer.getUUID()))); } } - - this.server.getPluginManager().callEvent(new PlayerHideEntityEvent(this, entity)); } void resetAndHideEntity(org.bukkit.entity.Entity entity) { @@ -1776,12 +1776,25 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } private void trackAndShowEntity(org.bukkit.entity.Entity entity) { + // Paper start - uuid override + this.trackAndShowEntity(entity, null); + } + private void trackAndShowEntity(org.bukkit.entity.Entity entity, final @Nullable UUID uuidOverride) { + // Paper end ChunkMap tracker = ((ServerLevel) this.getHandle().level()).getChunkSource().chunkMap; Entity other = ((CraftEntity) entity).getHandle(); if (other instanceof ServerPlayer) { ServerPlayer otherPlayer = (ServerPlayer) other; + // Paper start - uuid override + UUID original = null; + if (uuidOverride != null) { + original = otherPlayer.getUUID(); + otherPlayer.setUUID(uuidOverride); + } + // Paper end this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(otherPlayer))); + if (original != null) otherPlayer.setUUID(original); // Paper - uuid override } ChunkMap.TrackedEntity entry = tracker.entityMap.get(other.getId()); @@ -1791,6 +1804,39 @@ public class CraftPlayer extends CraftHumanEntity implements Player { this.server.getPluginManager().callEvent(new PlayerShowEntityEvent(this, entity)); } + // Paper start + @Override + public void setPlayerProfile(com.destroystokyo.paper.profile.PlayerProfile profile) { + ServerPlayer self = this.getHandle(); + GameProfile gameProfile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile); + if (!self.sentListPacket) { + self.gameProfile = gameProfile; + return; + } + List players = this.server.getServer().getPlayerList().players; + // First unregister the player for all players with the OLD game profile + for (ServerPlayer player : players) { + CraftPlayer bukkitPlayer = player.getBukkitEntity(); + if (bukkitPlayer.canSee(this)) { + bukkitPlayer.unregisterEntity(self); + } + } + + // Set the game profile here, we should have unregistered the entity via iterating all player entities above. + self.gameProfile = gameProfile; + + // Re-register the game profile for all players + for (ServerPlayer player : players) { + CraftPlayer bukkitPlayer = player.getBukkitEntity(); + if (bukkitPlayer.canSee(this)) { + bukkitPlayer.trackAndShowEntity(self.getBukkitEntity(), gameProfile.getId()); + } + } + + // Refresh misc player things AFTER sending game profile + this.refreshPlayer(); + } + // Paper end void resetAndShowEntity(org.bukkit.entity.Entity entity) { // SPIGOT-7312: Can't show/hide self @@ -1802,6 +1848,34 @@ public class CraftPlayer extends CraftHumanEntity implements Player { this.trackAndShowEntity(entity); } } + // Paper start + public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() { + return new com.destroystokyo.paper.profile.CraftPlayerProfile(this).clone(); + } + + private void refreshPlayer() { + ServerPlayer handle = this.getHandle(); + Location loc = this.getLocation(); + + ServerGamePacketListenerImpl connection = handle.connection; + + //Respawn the player then update their position and selected slot + ServerLevel worldserver = handle.serverLevel(); + connection.send(new net.minecraft.network.protocol.game.ClientboundRespawnPacket(handle.createCommonSpawnInfo(worldserver), net.minecraft.network.protocol.game.ClientboundRespawnPacket.KEEP_ALL_DATA)); + handle.onUpdateAbilities(); + connection.internalTeleport(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch(), java.util.Collections.emptySet()); + net.minecraft.server.players.PlayerList playerList = handle.server.getPlayerList(); + playerList.sendPlayerPermissionLevel(handle, false); + playerList.sendLevelInfo(handle, worldserver); + playerList.sendAllPlayerInfo(handle); + + // Resend their XP and effects because the respawn packet resets it + connection.send(new net.minecraft.network.protocol.game.ClientboundSetExperiencePacket(handle.experienceProgress, handle.totalExperience, handle.experienceLevel)); + for (net.minecraft.world.effect.MobEffectInstance mobEffect : handle.getActiveEffects()) { + connection.send(new net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket(handle.getId(), mobEffect)); + } + } + // Paper end public void onEntityRemove(Entity entity) { this.invertedVisibilityEntities.remove(entity.getUUID()); diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java index 457860fa9babe542347608a3fc11ad5d75e5d135..6a661bbae8bc35a4c3b4bb7e86dd77a7575fdd97 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java @@ -277,6 +277,13 @@ public class Commodore { return; } + // Paper start - Rewrite plugins + if ((owner.equals("org/bukkit/OfflinePlayer") || owner.equals("org/bukkit/entity/Player")) && name.equals("getPlayerProfile") && desc.equals("()Lorg/bukkit/profile/PlayerProfile;")) { + super.visitMethodInsn(opcode, owner, name, "()Lcom/destroystokyo/paper/profile/PlayerProfile;", itf); + return; + } + // Paper end + if (modern) { if (owner.equals("org/bukkit/Material") || (instantiatedMethodType != null && instantiatedMethodType.getDescriptor().startsWith("(Lorg/bukkit/Material;)"))) { switch (name) {