Commits

md_5 authored bb614f84146
SPIGOT-3724: Skull fixes from CraftBukkit
No tags

CraftBukkit-Patches/0087-Convert-player-skulls-async.patch

Modified
1 -From 216a5be97ac0a288850345b677a787dfd98dcfd2 Mon Sep 17 00:00:00 2001
1 +From 292bf189c31ce52e14f8d724767a5ea534a91a45 Mon Sep 17 00:00:00 2001
2 2 From: Thinkofdeath <thethinkofdeath@gmail.com>
3 3 Date: Sun, 20 Apr 2014 13:18:55 +0100
4 4 Subject: [PATCH] Convert player skulls async
5 5
6 6
7 7 diff --git a/src/main/java/net/minecraft/server/ItemSkull.java b/src/main/java/net/minecraft/server/ItemSkull.java
8 -index cbb902f50..bd99b5a18 100644
8 +index cbb902f50..ca33c9c13 100644
9 9 --- a/src/main/java/net/minecraft/server/ItemSkull.java
10 10 +++ b/src/main/java/net/minecraft/server/ItemSkull.java
11 11 @@ -124,13 +124,21 @@ public class ItemSkull extends Item {
12 12 return super.b(itemstack);
13 13 }
14 14
15 15 - public boolean a(NBTTagCompound nbttagcompound) {
16 16 + public boolean a(final NBTTagCompound nbttagcompound) { // Spigot - make final
17 17 super.a(nbttagcompound);
18 18 if (nbttagcompound.hasKeyOfType("SkullOwner", 8) && !StringUtils.isBlank(nbttagcompound.getString("SkullOwner"))) {
19 19 GameProfile gameprofile = new GameProfile((UUID) null, nbttagcompound.getString("SkullOwner"));
20 20
21 21 - gameprofile = TileEntitySkull.b(gameprofile);
22 22 - nbttagcompound.set("SkullOwner", GameProfileSerializer.serialize(new NBTTagCompound(), gameprofile));
23 23 + // Spigot start
24 24 + TileEntitySkull.b(gameprofile, new com.google.common.base.Predicate<GameProfile>() {
25 25 +
26 26 + @Override
27 27 + public boolean apply(GameProfile gameprofile) {
28 -+ nbttagcompound.set("SkullOwner", GameProfileSerializer.serialize(new NBTTagCompound(), gameprofile));
28 ++ nbttagcompound.set("SkullOwner", GameProfileSerializer.serialize(new NBTTagCompound(), gameprofile));
29 29 + return false;
30 30 + }
31 31 + });
32 32 + // Spigot end
33 33 return true;
34 34 } else {
35 35 // CraftBukkit start
36 36 diff --git a/src/main/java/net/minecraft/server/TileEntitySkull.java b/src/main/java/net/minecraft/server/TileEntitySkull.java
37 -index 223e2ed2d..fd08e0bdc 100644
37 +index 223e2ed2d..1e3c687d6 100644
38 38 --- a/src/main/java/net/minecraft/server/TileEntitySkull.java
39 39 +++ b/src/main/java/net/minecraft/server/TileEntitySkull.java
40 -@@ -7,6 +7,20 @@ import com.mojang.authlib.properties.Property;
40 +@@ -7,6 +7,23 @@ import com.mojang.authlib.properties.Property;
41 41 import java.util.UUID;
42 42 import javax.annotation.Nullable;
43 43
44 44 +// Spigot start
45 45 +import com.google.common.base.Predicate;
46 46 +import com.google.common.cache.LoadingCache;
47 47 +import com.google.common.cache.CacheBuilder;
48 48 +import com.google.common.cache.CacheLoader;
49 -+import java.util.concurrent.Executor;
49 ++import com.google.common.util.concurrent.Futures;
50 50 +import java.util.concurrent.Executors;
51 ++import java.util.concurrent.ExecutorService;
52 ++import java.util.concurrent.Future;
51 53 +import java.util.concurrent.TimeUnit;
52 54 +
53 55 +import com.google.common.util.concurrent.ThreadFactoryBuilder;
54 56 +import com.mojang.authlib.Agent;
55 57 +import com.mojang.authlib.ProfileLookupCallback;
58 ++import java.util.concurrent.Callable;
56 59 +// Spigot end
57 60 +
58 61 public class TileEntitySkull extends TileEntity implements ITickable {
59 62
60 63 private int a;
61 -@@ -16,6 +30,58 @@ public class TileEntitySkull extends TileEntity implements ITickable {
64 +@@ -16,6 +33,58 @@ public class TileEntitySkull extends TileEntity implements ITickable {
62 65 private boolean i;
63 66 private static UserCache j;
64 67 private static MinecraftSessionService k;
65 68 + // Spigot start
66 -+ public static final Executor executor = Executors.newFixedThreadPool(3,
69 ++ public static final ExecutorService executor = Executors.newFixedThreadPool(3,
67 70 + new ThreadFactoryBuilder()
68 71 + .setNameFormat("Head Conversion Thread - %1$d")
69 72 + .build()
70 73 + );
71 74 + public static final LoadingCache<String, GameProfile> skinCache = CacheBuilder.newBuilder()
72 75 + .maximumSize( 5000 )
73 76 + .expireAfterAccess( 60, TimeUnit.MINUTES )
74 77 + .build( new CacheLoader<String, GameProfile>()
75 78 + {
76 79 + @Override
110 113 + }
111 114 +
112 115 +
113 116 + return profile;
114 117 + }
115 118 + } );
116 119 + // Spigot end
117 120
118 121 public TileEntitySkull() {}
119 122
120 -@@ -98,35 +164,60 @@ public class TileEntitySkull extends TileEntity implements ITickable {
123 +@@ -98,35 +167,65 @@ public class TileEntitySkull extends TileEntity implements ITickable {
121 124 }
122 125
123 126 private void i() {
124 127 - this.g = b(this.g);
125 128 - this.update();
126 129 + // Spigot start
127 130 + GameProfile profile = this.g;
128 131 + setSkullType( 0 ); // Work around client bug
129 132 + b(profile, new Predicate<GameProfile>() {
130 133 +
137 140 + world.m(position); // PAIL: notify
138 141 + }
139 142 + return false;
140 143 + }
141 144 + });
142 145 + // Spigot end
143 146 }
144 147
145 148 - public static GameProfile b(GameProfile gameprofile) {
146 149 + // Spigot start - Support async lookups
147 -+ public static void b(final GameProfile gameprofile, final Predicate<GameProfile> callback) {
150 ++ public static Future<GameProfile> b(final GameProfile gameprofile, final Predicate<GameProfile> callback) {
148 151 if (gameprofile != null && !UtilColor.b(gameprofile.getName())) {
149 152 if (gameprofile.isComplete() && gameprofile.getProperties().containsKey("textures")) {
150 153 - return gameprofile;
151 154 - } else if (TileEntitySkull.j != null && TileEntitySkull.k != null) {
152 155 - GameProfile gameprofile1 = TileEntitySkull.j.getProfile(gameprofile.getName());
153 --
154 -- if (gameprofile1 == null) {
155 -- return gameprofile;
156 156 + callback.apply(gameprofile);
157 157 + } else if (MinecraftServer.getServer() == null) {
158 158 + callback.apply(gameprofile);
159 159 + } else {
160 160 + GameProfile profile = skinCache.getIfPresent(gameprofile.getName().toLowerCase(java.util.Locale.ROOT));
161 161 + if (profile != null && Iterables.getFirst(profile.getProperties().get("textures"), (Object) null) != null) {
162 162 + callback.apply(profile);
163 +
164 +- if (gameprofile1 == null) {
165 +- return gameprofile;
166 ++ return Futures.immediateFuture(profile);
163 167 } else {
164 168 - Property property = (Property) Iterables.getFirst(gameprofile1.getProperties().get("textures"), (Object) null);
165 169 -
166 170 - if (property == null) {
167 171 - gameprofile1 = TileEntitySkull.k.fillProfileProperties(gameprofile1, true);
168 172 - }
169 173 -
170 174 - return gameprofile1;
171 -+ executor.execute(new Runnable() {
175 ++ return executor.submit(new Callable<GameProfile>() {
172 176 + @Override
173 -+ public void run() {
177 ++ public GameProfile call() {
174 178 + final GameProfile profile = skinCache.getUnchecked(gameprofile.getName().toLowerCase(java.util.Locale.ROOT));
175 179 + MinecraftServer.getServer().processQueue.add(new Runnable() {
176 180 + @Override
177 181 + public void run() {
178 182 + if (profile == null) {
179 183 + callback.apply(gameprofile);
180 184 + } else {
181 185 + callback.apply(profile);
182 186 + }
183 187 + }
184 188 + });
189 ++ return profile;
185 190 + }
186 191 + });
187 192 }
188 193 - } else {
189 194 - return gameprofile;
190 195 }
191 196 } else {
192 197 - return gameprofile;
193 198 + callback.apply(gameprofile);
194 199 }
200 ++
201 ++ return Futures.immediateFuture(gameprofile);
195 202 }
196 203 + // Spigot end
197 204
198 205 public int getSkullType() {
199 206 return this.a;
200 207 diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
201 -index fbc16890c..4976eb26a 100644
208 +index 8c5d3effc..8a58615f8 100644
202 209 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
203 210 +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
204 -@@ -5,6 +5,7 @@ import java.util.Map;
205 - import net.minecraft.server.GameProfileSerializer;
206 - import net.minecraft.server.NBTBase;
207 - import net.minecraft.server.NBTTagCompound;
208 -+import net.minecraft.server.TileEntitySkull;
209 -
210 - import org.bukkit.Bukkit;
211 - import org.bukkit.Material;
212 -@@ -71,13 +72,27 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
213 - }
214 -
215 - @Override
216 -- void applyToItem(NBTTagCompound tag) {
217 -+ void applyToItem(final NBTTagCompound tag) { // Spigot - make final
218 - super.applyToItem(tag);
211 +@@ -77,7 +77,8 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
219 212
220 213 if (profile != null) {
214 + // Fill in textures
215 +- profile = TileEntitySkull.b(profile);
216 ++ // Must be done sync due to way client handles textures
217 ++ profile = com.google.common.util.concurrent.Futures.getUnchecked(TileEntitySkull.b(profile, com.google.common.base.Predicates.alwaysTrue())); // Spigot
218 +
221 219 NBTTagCompound owner = new NBTTagCompound();
222 220 GameProfileSerializer.serialize(owner, profile);
223 -- tag.set(SKULL_OWNER.NBT, owner);
224 -+ tag.set( SKULL_OWNER.NBT, owner );
225 -+ // Spigot start - do an async lookup of the profile.
226 -+ // Unfortunately there is not way to refresh the holding
227 -+ // inventory, so that responsibility is left to the user.
228 -+ net.minecraft.server.TileEntitySkull.b(profile, new com.google.common.base.Predicate<GameProfile>() {
229 -+
230 -+ @Override
231 -+ public boolean apply(GameProfile input) {
232 -+ NBTTagCompound owner = new NBTTagCompound();
233 -+ GameProfileSerializer.serialize( owner, input );
234 -+ tag.set( SKULL_OWNER.NBT, owner );
235 -+ return false;
236 -+ }
237 -+ });
238 -+ // Spigot end
239 - }
240 - }
241 -
242 -@@ -136,7 +151,10 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
243 - if (name == null) {
244 - profile = null;
245 - } else {
246 -- profile = new GameProfile(null, name);
247 -+ // Spigot start
248 -+ profile = TileEntitySkull.skinCache.getIfPresent(name.toLowerCase(java.util.Locale.ROOT));
249 -+ if (profile == null) profile = new GameProfile(null, name);
250 -+ // Spigot end
251 - }
252 -
253 - return true;
254 221 --
255 222 2.14.1
256 223

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut