From a70618cd5cb493fe9fe2a2a7375a7b1949d427d7 Mon Sep 17 00:00:00 2001 From: Aikar Date: Fri, 19 Jun 2020 21:32:42 -0400 Subject: [PATCH] Make Skull Texture Lookup use the User Cache Spigots cache only cached by name which really was not correct... Additionally, user cache exposes a cache of any player who has logged in once this session too even if offline. Also fixed some quirks with Profile API where we might of had textures in the cache that we didn't even try to look up. So this should overall help reduce API calls to Mojang. Sadly, the User Cache doesn't cache textures, but if that ever changes in future, we would gain benefit there too. --- .../0154-Basic-PlayerProfile-API.patch | 99 ++++++++++++++++--- ...-Add-setPlayerProfile-API-for-Skulls.patch | 4 +- 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/Spigot-Server-Patches/0154-Basic-PlayerProfile-API.patch b/Spigot-Server-Patches/0154-Basic-PlayerProfile-API.patch index 59a1ff797a..0fb3a82843 100644 --- a/Spigot-Server-Patches/0154-Basic-PlayerProfile-API.patch +++ b/Spigot-Server-Patches/0154-Basic-PlayerProfile-API.patch @@ -7,10 +7,10 @@ Establishes base extension of profile systems for future edits too diff --git a/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java b/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java new file mode 100644 -index 0000000000000000000000000000000000000000..b151a13c1b9058eb057081ef8a64558028443a07 +index 0000000000000000000000000000000000000000..5eee712e4c9230b10a969daee9fd8b4eec9bf6c9 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java -@@ -0,0 +1,280 @@ +@@ -0,0 +1,285 @@ +package com.destroystokyo.paper.profile; + +import com.destroystokyo.paper.PaperConfig; @@ -151,9 +151,6 @@ index 0000000000000000000000000000000000000000..b151a13c1b9058eb057081ef8a645580 + } + + public boolean completeFromCache(boolean lookupName) { -+ if (profile.isComplete()) { -+ return true; -+ } + MinecraftServer server = MinecraftServer.getServer(); + String name = profile.getName(); + UserCache userCache = server.getUserCache(); @@ -167,14 +164,17 @@ index 0000000000000000000000000000000000000000..b151a13c1b9058eb057081ef8a645580 + profile = new GameProfile(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)), name); + } + if (profile != null) { ++ // if old has it, assume its newer, so overwrite, else use cached if it was set and ours wasn't ++ copyProfileProperties(this.profile, profile); + this.profile = profile; + } + } + -+ if (profile.getName() == null) { -+ // If we need textures, skip this check, as we will get it below anyways. ++ if (profile.getName() == null || !hasTextures()) { + GameProfile profile = userCache.getProfile(this.profile.getId()); + if (profile != null) { ++ // if old has it, assume its newer, so overwrite, else use cached if it was set and ours wasn't ++ copyProfileProperties(this.profile, profile); + this.profile = profile; + } + } @@ -189,22 +189,27 @@ index 0000000000000000000000000000000000000000..b151a13c1b9058eb057081ef8a645580 + if (isOnlineMode && (!isCompleteFromCache || textures && !hasTextures())) { + GameProfile result = server.getSessionService().fillProfileProperties(profile, true); + if (result != null) { -+ this.profile = result; ++ copyProfileProperties(result, this.profile, true); + } ++ server.getUserCache().saveProfile(this.profile); + } + return profile.isComplete() && (!isOnlineMode || !textures || hasTextures()); + } + + private static void copyProfileProperties(GameProfile source, GameProfile target) { ++ copyProfileProperties(source, target, false); ++ } ++ ++ private static void copyProfileProperties(GameProfile source, GameProfile target, boolean clearTarget) { + PropertyMap sourceProperties = source.getProperties(); ++ PropertyMap targetProperties = target.getProperties(); ++ if (clearTarget) targetProperties.clear(); + if (sourceProperties.isEmpty()) { + return; + } -+ PropertyMap properties = target.getProperties(); -+ properties.clear(); + + for (Property property : sourceProperties.values()) { -+ properties.put(property.getName(), property); ++ targetProperties.put(property.getName(), property); + } + } + @@ -450,8 +455,50 @@ index ed32242bd169e9f28607942aa31aa48a5799b215..54f80cb8e1b771f2a493543e04f8bc83 public MinecraftSessionService getMinecraftSessionService() { return this.minecraftSessionService; } +diff --git a/src/main/java/net/minecraft/server/TileEntitySkull.java b/src/main/java/net/minecraft/server/TileEntitySkull.java +index 177cceb77f8783fe93ba7e4342de9c589f155c1b..e2544aeb5a28fd98a4dc162227276b23a99424fc 100644 +--- a/src/main/java/net/minecraft/server/TileEntitySkull.java ++++ b/src/main/java/net/minecraft/server/TileEntitySkull.java +@@ -158,6 +158,7 @@ public class TileEntitySkull extends TileEntity /*implements ITickable*/ { // Pa + private void f() { + // Spigot start + GameProfile profile = this.gameProfile; ++ if (profile.isComplete() && profile.getProperties().containsKey("textures")) return; // Paper + b(profile, new Predicate() { + + @Override +@@ -178,7 +179,16 @@ public class TileEntitySkull extends TileEntity /*implements ITickable*/ { // Pa + } else if (MinecraftServer.getServer() == null) { + callback.apply(gameprofile); + } else { +- GameProfile profile = skinCache.getIfPresent(gameprofile.getName().toLowerCase(java.util.Locale.ROOT)); ++ // Paper start ++ com.destroystokyo.paper.profile.CraftPlayerProfile paperProfile = new com.destroystokyo.paper.profile.CraftPlayerProfile(gameprofile); ++ if (sync) { ++ // might complete by cache, but if not, go ahead and do it now, avoid the code below ++ paperProfile.complete(true); ++ } else { ++ paperProfile.completeFromCache(); ++ } ++ GameProfile profile = paperProfile.getGameProfile(); ++ // Paper end + if (profile != null && Iterables.getFirst(profile.getProperties().get("textures"), (Object) null) != null) { + callback.apply(profile); + +@@ -187,7 +197,10 @@ public class TileEntitySkull extends TileEntity /*implements ITickable*/ { // Pa + Callable callable = new Callable() { + @Override + public GameProfile call() { +- final GameProfile profile = skinCache.getUnchecked(gameprofile.getName().toLowerCase(java.util.Locale.ROOT)); ++ // Paper start ++ paperProfile.complete(true); ++ final GameProfile profile = paperProfile.getGameProfile(); ++ // Paper end + MinecraftServer.getServer().processQueue.add(new Runnable() { + @Override + public void run() { diff --git a/src/main/java/net/minecraft/server/UserCache.java b/src/main/java/net/minecraft/server/UserCache.java -index 581199e6dcddb3692ccc6b6cf6c42fa5ef1f5e7e..a072222bc5b8b1b62990bce35034b09ebf270865 100644 +index 581199e6dcddb3692ccc6b6cf6c42fa5ef1f5e7e..39d2f83531d539fb96824c2e6a9018c12ea75272 100644 --- a/src/main/java/net/minecraft/server/UserCache.java +++ b/src/main/java/net/minecraft/server/UserCache.java @@ -43,7 +43,7 @@ public class UserCache { @@ -463,7 +510,15 @@ index 581199e6dcddb3692ccc6b6cf6c42fa5ef1f5e7e..a072222bc5b8b1b62990bce35034b09e private final Map e = new java.util.concurrent.ConcurrentHashMap<>(); // Paper private final Deque f = new java.util.concurrent.LinkedBlockingDeque(); // CraftBukkit private final GameProfileRepository g; -@@ -165,6 +165,13 @@ public class UserCache { +@@ -104,6 +104,7 @@ public class UserCache { + return UserCache.c; + } + ++ public void saveProfile(GameProfile gameprofile) { a(gameprofile); } // Paper - OBFHELPER + public void a(GameProfile gameprofile) { + this.a(gameprofile, (Date) null); + } +@@ -165,6 +166,13 @@ public class UserCache { return usercache_usercacheentry == null ? null : usercache_usercacheentry.a(); } @@ -477,7 +532,7 @@ index 581199e6dcddb3692ccc6b6cf6c42fa5ef1f5e7e..a072222bc5b8b1b62990bce35034b09e @Nullable public GameProfile getProfile(UUID uuid) { UserCache.UserCacheEntry usercache_usercacheentry = (UserCache.UserCacheEntry) this.e.get(uuid); -@@ -273,7 +280,7 @@ public class UserCache { +@@ -273,7 +281,7 @@ public class UserCache { class UserCacheEntry { @@ -525,3 +580,19 @@ index f01bd38d0b600a69224f610fd77a542ec6d1c322..95f4abddf57eb8c59cb5a5410b8d551d + } // Paper end } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java +index 4fb27cc7ed062696239f75b6f85ddb0a31866568..52c8d31590ea8e355395fa95cf690cc3770f5f71 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java +@@ -71,6 +71,11 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta { + } + + private void setProfile(GameProfile profile) { ++ // Paper start ++ com.destroystokyo.paper.profile.CraftPlayerProfile paperProfile = new com.destroystokyo.paper.profile.CraftPlayerProfile(profile); ++ paperProfile.completeFromCache(); ++ profile = paperProfile.getGameProfile(); ++ // Paper end + this.profile = profile; + this.serializedProfile = (profile == null) ? null : GameProfileSerializer.serialize(new NBTTagCompound(), profile); + } diff --git a/Spigot-Server-Patches/0191-Add-setPlayerProfile-API-for-Skulls.patch b/Spigot-Server-Patches/0191-Add-setPlayerProfile-API-for-Skulls.patch index 03e42d479a..2e893431db 100644 --- a/Spigot-Server-Patches/0191-Add-setPlayerProfile-API-for-Skulls.patch +++ b/Spigot-Server-Patches/0191-Add-setPlayerProfile-API-for-Skulls.patch @@ -48,7 +48,7 @@ index 20588598386a4f479e6a58b294149bed789c63ce..ecc32c2fb1e8e1ac03074102b982adb4 public BlockFace getRotation() { BlockData blockData = getBlockData(); diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -index 4fb27cc7ed062696239f75b6f85ddb0a31866568..96d62bbf883cf589509d51ac02fbe11a452dce64 100644 +index 52c8d31590ea8e355395fa95cf690cc3770f5f71..2a3c86b0cbce0c37ebd8cace138c72c99f7455ea 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java @@ -3,6 +3,8 @@ package org.bukkit.craftbukkit.inventory; @@ -68,7 +68,7 @@ index 4fb27cc7ed062696239f75b6f85ddb0a31866568..96d62bbf883cf589509d51ac02fbe11a @DelegateDeserialization(SerializableMeta.class) class CraftMetaSkull extends CraftMetaItem implements SkullMeta { -@@ -133,6 +136,19 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta { +@@ -138,6 +141,19 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta { return hasOwner() ? profile.getName() : null; }