Paper/patches/server/0181-Player.setPlayerProfile-API.patch
2024-04-27 13:27:01 -07:00

240 lines
13 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
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 ae0e3694f3971908cb472b1165d2649265e1bdca..66ca4d1f28143d1e4ce99532c6c2bd64cde67024 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1459,7 +1459,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<RelativeMovement> set) {
+ public void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<RelativeMovement> 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 43c77bef408c016ee40454bdebb8662929a0b7f0..2ca467bd9c53a59f1ca9b8e1c2cf683182a71910 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -334,11 +334,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 d59f85d3a4385ebba1a93a9b10533f18b7386ab2..d25c762e449e2bce20487454ad52363b35b9af96 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 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 791b655890ce5b144f8649f687945c17a390ce76..ea82243ea965ee70ef1f94cb699d9ab262415b7a 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -247,11 +247,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;
@@ -1774,8 +1769,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());
@@ -1788,8 +1790,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) {
@@ -1854,12 +1854,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());
@@ -1869,6 +1882,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<ServerPlayer> 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
@@ -1880,6 +1926,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 fc04bfcb8b5dfa6d093c8d75b2f20c502ef94a63..07239f25bc927c44a9d17f4796db3a107b8e14e0 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java
@@ -378,6 +378,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) {