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 61f6a2449b6fa52eef597f8725ae076bd23cd8ea..ecc2ce39629f6edbd09e96c85e14ab2196ac3173 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1472,7 +1472,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 2d9db1ac80216a509a7590254e422b3c4792e3ec..b31f00f2f0b7cec59301afe36c9dd7cdc120fc9d 100644 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -336,11 +336,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, this.transferred, 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 5375fd660e3ed4a5997896d28ea234a81d183a10..e959c7e45bffdcf46908a6919c07a0cdf9aa83bb 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -831,10 +831,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 818df09e9245b5d89b4180b1eaa51470b7539341..461656e1cb095243bfe7a9ee2906e5b00574ae78 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 aaef5693b044141d2aa8108b74b240903c64e6e6..a6567aa9a3ec9dd17689e907131e5cca05da7c9d 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -249,11 +249,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.protocol() == null) return null; @@ -1791,8 +1786,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()); @@ -1805,8 +1807,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) { @@ -1871,12 +1871,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()); @@ -1886,6 +1899,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 @@ -1897,6 +1943,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, false)); + } + } + // 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 e8bdc9f97cc506ca8509480ea0c07facc778df8d..2d9453498531c99f4fa566a08099b4e5a7af25fa 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java @@ -379,6 +379,13 @@ public class Commodore { } // Paper end - Rewrite plugins + // 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) {