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 b5abb0d433322224ccbbed8755fb3ebf77b5a36c..598b442f84df4562811986cfb5e8614e74df2cc0 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1438,7 +1438,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 41ba6f0c88b6205bf33de962c0bc545a0ac40c74..03ff64ad395455f21f4ca30faae17fc6a1dc0501 100644 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -293,11 +293,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, final org.bukkit.craftbukkit.CraftServer server = ServerLoginPacketListenerImpl.this.server.server; // Paper start - 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); AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId, profile); 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/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java index 477d3245facb5ae59c786d4f696f64226cb540a6..e8490a58dd4d9bc39a5bb2f9fc109526e031b971 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java @@ -81,8 +81,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 317f879a1be75ae77a0cc52dece1ef3530cde786..601153fac20f6f15aa09bbc8bc63995e43494611 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -271,11 +271,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; @@ -1690,8 +1685,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()); @@ -1704,8 +1706,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) { @@ -1770,12 +1770,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()); @@ -1785,6 +1798,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 @@ -1796,6 +1842,36 @@ 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(new net.minecraft.network.protocol.game.CommonPlayerSpawnInfo(worldserver.dimensionTypeId(), worldserver.dimension(), net.minecraft.world.level.biome.BiomeManager.obfuscateSeed(worldserver.getSeed()), handle.gameMode.getGameModeForPlayer(), handle.gameMode.getPreviousGameModeForPlayer(), worldserver.isDebug(), worldserver.isFlat(), handle.getLastDeathLocation(), handle.getPortalCooldown()), 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.MinecraftServer.getServer().getPlayerList().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)); + } + + if (this.isOp()) { + this.setOp(false); + this.setOp(true); + } + } + // 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 3b6683e778a35d021d6189bf8ee5719684040665..4b209818a20e76e9d857c4bb822f6b24ec8e9f09 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java @@ -338,6 +338,12 @@ 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" ) )