Paper/CraftBukkit-Patches/0131-Convert-player-skulls-async.patch
Zach Brown cab333b217 Rebase (Update) from upstream SpigotMC
Don't send requests of every player was found in the global api cache SpigotMC/Spigot@841270ff1e
Correctly set the response code for the cached lookups and return the ... SpigotMC/Spigot@f170b7899c
Don't try and re-set the global api cache on reload SpigotMC/Spigot@b410a00a66
Use a compile time sneaky throw hack. SpigotMC/Spigot@508462b96b
Fix a missed rename in WorldGenGroundBush SpigotMC/Spigot@0614d8fae9
2014-11-28 14:19:07 -06:00

249 lines
10 KiB
Diff

From 9a18280069d9e62073e94dddba10714c382583a3 Mon Sep 17 00:00:00 2001
From: Thinkofdeath <thethinkofdeath@gmail.com>
Date: Sun, 20 Apr 2014 13:18:55 +0100
Subject: [PATCH] Convert player skulls async
diff --git a/src/main/java/net/minecraft/server/ItemStack.java b/src/main/java/net/minecraft/server/ItemStack.java
index 7d2d401..ee82aba 100644
--- a/src/main/java/net/minecraft/server/ItemStack.java
+++ b/src/main/java/net/minecraft/server/ItemStack.java
@@ -216,9 +216,61 @@ public final class ItemStack {
if (nbttagcompound.hasKeyOfType("tag", 10)) {
// CraftBukkit - make defensive copy as this data may be coming from the save thread
this.tag = (NBTTagCompound) nbttagcompound.getCompound("tag").clone();
+ validateSkullSkin(); // Spigot
}
}
+ // Spigot start - make sure the tag is given the full gameprofile if it's a skull (async lookup)
+ public void validateSkullSkin()
+ {
+ if ( this.item == Items.SKULL && this.getData() == 3 )
+ {
+ String owner;
+ if ( this.tag.hasKeyOfType( "SkullOwner", 8 ) )
+ {
+ owner = this.tag.getString( "SkullOwner" );
+ } else if ( this.tag.hasKeyOfType( "SkullOwner", 10 ) )
+ {
+ net.minecraft.util.com.mojang.authlib.GameProfile profile = GameProfileSerializer.deserialize( this.tag.getCompound( "SkullOwner" ) );
+ if ( profile == null || !profile.getProperties().isEmpty() )
+ {
+ return;
+ } else
+ {
+ owner = profile.getName();
+ }
+ } else
+ {
+ return;
+ }
+
+ final String finalOwner = owner;
+ TileEntitySkull.executor.execute( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+
+ final net.minecraft.util.com.mojang.authlib.GameProfile profile = TileEntitySkull.skinCache.getUnchecked( finalOwner.toLowerCase() );
+ if ( profile != null )
+ {
+ MinecraftServer.getServer().processQueue.add( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ NBTTagCompound nbtProfile = new NBTTagCompound();
+ GameProfileSerializer.serialize( nbtProfile, profile );
+ ItemStack.this.tag.set( "SkullOwner", nbtProfile );
+ }
+ } );
+ }
+ }
+ } );
+ }
+ }
+ // Spigot end
+
public int getMaxStackSize() {
return this.getItem().getMaxStackSize();
}
@@ -457,6 +509,7 @@ public final class ItemStack {
public void setTag(NBTTagCompound nbttagcompound) {
this.tag = nbttagcompound;
+ validateSkullSkin(); // Spigot
}
public String getName() {
diff --git a/src/main/java/net/minecraft/server/TileEntitySkull.java b/src/main/java/net/minecraft/server/TileEntitySkull.java
index 2a50db9..1796a56 100644
--- a/src/main/java/net/minecraft/server/TileEntitySkull.java
+++ b/src/main/java/net/minecraft/server/TileEntitySkull.java
@@ -6,11 +6,64 @@ import net.minecraft.util.com.google.common.collect.Iterables;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import net.minecraft.util.com.mojang.authlib.properties.Property;
+// Spigot start
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import net.minecraft.util.com.mojang.authlib.Agent;
+// Spigot end
+
public class TileEntitySkull extends TileEntity {
private int a;
private int i;
private GameProfile j = null;
+ // Spigot start
+ public static final Executor executor = Executors.newFixedThreadPool(3,
+ new ThreadFactoryBuilder()
+ .setNameFormat("Head Conversion Thread - %1$d")
+ .build()
+ );
+ public static final Cache<String, GameProfile> skinCache = CacheBuilder.newBuilder()
+ .maximumSize( 5000 )
+ .expireAfterAccess( 60, TimeUnit.MINUTES )
+ .build( new CacheLoader<String, GameProfile>()
+ {
+ @Override
+ public GameProfile load(String key) throws Exception
+ {
+ GameProfile[] profiles = new GameProfile[1];
+ GameProfileLookup gameProfileLookup = new GameProfileLookup(profiles);
+
+ MinecraftServer.getServer().getGameProfileRepository().findProfilesByNames(new String[] { key }, Agent.MINECRAFT, gameProfileLookup);
+
+ GameProfile profile = profiles[ 0 ];
+ if (profile == null) {
+ UUID uuid = EntityHuman.a(new GameProfile(null, key));
+ profile = new GameProfile(uuid, key);
+
+ gameProfileLookup.onProfileLookupSucceeded(profile);
+ } else
+ {
+
+ Property property = Iterables.getFirst( profile.getProperties().get( "textures" ), null );
+
+ if ( property == null )
+ {
+ profile = MinecraftServer.getServer().av().fillProfileProperties( profile, true );
+ }
+ }
+
+
+ return profile;
+ }
+ } );
+ // Spigot end
public TileEntitySkull() {}
@@ -66,18 +119,38 @@ public class TileEntitySkull extends TileEntity {
private void d() {
if (this.j != null && !UtilColor.b(this.j.getName())) {
if (!this.j.isComplete() || !this.j.getProperties().containsKey("textures")) {
- GameProfile gameprofile = MinecraftServer.getServer().getUserCache().getProfile(this.j.getName());
-
- if (gameprofile != null) {
- Property property = (Property) Iterables.getFirst(gameprofile.getProperties().get("textures"), null);
-
- if (property == null) {
- gameprofile = MinecraftServer.getServer().av().fillProfileProperties(gameprofile, true);
+ // Spigot start - Handle async
+ final String name = this.j.getName();
+ setSkullType( 0 ); // Work around a client bug
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+
+ GameProfile profile = skinCache.getUnchecked( name.toLowerCase() );
+
+ if (profile != null) {
+ final GameProfile finalProfile = profile;
+ MinecraftServer.getServer().processQueue.add(new Runnable() {
+ @Override
+ public void run() {
+ a = 3;
+ j = finalProfile;
+ world.notify( x, y, z );
+ }
+ });
+ } else {
+ MinecraftServer.getServer().processQueue.add(new Runnable() {
+ @Override
+ public void run() {
+ a = 3;
+ j = new GameProfile( null, name );
+ world.notify( x, y, z );
+ }
+ });
+ }
}
-
- this.j = gameprofile;
- this.update();
- }
+ });
+ // Spigot end
}
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
index d648d05..e32bcb1 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
@@ -46,13 +46,39 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
}
@Override
- void applyToItem(NBTTagCompound tag) {
+ void applyToItem(final NBTTagCompound tag) { // Spigot - make final
super.applyToItem(tag);
if (hasOwner()) {
NBTTagCompound owner = new NBTTagCompound();
GameProfileSerializer.serialize(owner, profile);
- tag.set(SKULL_OWNER.NBT, owner);
+ tag.set( SKULL_OWNER.NBT, owner );
+ // Spigot start - do an async lookup of the profile.
+ // Unfortunately there is not way to refresh the holding
+ // inventory, so that responsibility is left to the user.
+ net.minecraft.server.TileEntitySkull.executor.execute( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+
+ final GameProfile profile = net.minecraft.server.TileEntitySkull.skinCache.getUnchecked( CraftMetaSkull.this.profile.getName().toLowerCase() );
+ if ( profile != null )
+ {
+ MinecraftServer.getServer().processQueue.add( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ NBTTagCompound owner = new NBTTagCompound();
+ GameProfileSerializer.serialize( owner, profile );
+ tag.set( SKULL_OWNER.NBT, owner );
+ }
+ } );
+ }
+ }
+ } );
+ // Spigot end
}
}
--
1.9.1