2014-07-29 21:59:47 +02:00
|
|
|
From a9c0273e82c8e1ea6a93e66482b23d7b74061c0d Mon Sep 17 00:00:00 2001
|
2014-07-21 22:46:54 +02:00
|
|
|
From: Thinkofdeath <thethinkofdeath@gmail.com>
|
|
|
|
Date: Sun, 20 Apr 2014 13:18:55 +0100
|
|
|
|
Subject: [PATCH] Convert player skulls async
|
|
|
|
|
|
|
|
|
2014-07-27 21:14:24 +02:00
|
|
|
diff --git a/src/main/java/net/minecraft/server/ItemStack.java b/src/main/java/net/minecraft/server/ItemStack.java
|
2014-07-29 21:59:47 +02:00
|
|
|
index 7d2d401..ee82aba 100644
|
2014-07-27 21:14:24 +02:00
|
|
|
--- 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() {
|
2014-07-21 22:46:54 +02:00
|
|
|
diff --git a/src/main/java/net/minecraft/server/TileEntitySkull.java b/src/main/java/net/minecraft/server/TileEntitySkull.java
|
2014-07-29 21:59:47 +02:00
|
|
|
index 2a50db9..1796a56 100644
|
2014-07-21 22:46:54 +02:00
|
|
|
--- a/src/main/java/net/minecraft/server/TileEntitySkull.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/TileEntitySkull.java
|
2014-07-29 21:59:47 +02:00
|
|
|
@@ -6,11 +6,64 @@ import net.minecraft.util.com.google.common.collect.Iterables;
|
2014-07-21 22:46:54 +02:00
|
|
|
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
|
2014-07-27 21:14:24 +02:00
|
|
|
+ public static final Executor executor = Executors.newFixedThreadPool(3,
|
2014-07-21 22:46:54 +02:00
|
|
|
+ new ThreadFactoryBuilder()
|
|
|
|
+ .setNameFormat("Head Conversion Thread - %1$d")
|
|
|
|
+ .build()
|
|
|
|
+ );
|
2014-07-27 21:14:24 +02:00
|
|
|
+ public static final Cache<String, GameProfile> skinCache = CacheBuilder.newBuilder()
|
2014-07-21 22:46:54 +02:00
|
|
|
+ .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);
|
2014-07-29 21:59:47 +02:00
|
|
|
+
|
|
|
|
+ GameProfile profile = profiles[ 0 ];
|
|
|
|
+ if (profile == null) {
|
2014-07-21 22:46:54 +02:00
|
|
|
+ UUID uuid = EntityHuman.a(new GameProfile(null, key));
|
2014-07-29 21:59:47 +02:00
|
|
|
+ profile = new GameProfile(uuid, key);
|
2014-07-21 22:46:54 +02:00
|
|
|
+
|
|
|
|
+ gameProfileLookup.onProfileLookupSucceeded(profile);
|
2014-07-29 21:59:47 +02:00
|
|
|
+ } else
|
|
|
|
+ {
|
2014-07-21 22:46:54 +02:00
|
|
|
+
|
2014-07-29 21:59:47 +02:00
|
|
|
+ Property property = Iterables.getFirst( profile.getProperties().get( "textures" ), null );
|
2014-07-21 22:46:54 +02:00
|
|
|
+
|
2014-07-29 21:59:47 +02:00
|
|
|
+ if ( property == null )
|
|
|
|
+ {
|
|
|
|
+ profile = MinecraftServer.getServer().av().fillProfileProperties( profile, true );
|
|
|
|
+ }
|
2014-07-21 22:46:54 +02:00
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ return profile;
|
|
|
|
+ }
|
|
|
|
+ } );
|
|
|
|
+ // Spigot end
|
|
|
|
|
|
|
|
public TileEntitySkull() {}
|
|
|
|
|
2014-07-29 21:59:47 +02:00
|
|
|
@@ -66,18 +119,38 @@ public class TileEntitySkull extends TileEntity {
|
2014-07-21 22:46:54 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-27 21:14:24 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-21 22:46:54 +02:00
|
|
|
--
|
2014-07-29 21:59:47 +02:00
|
|
|
1.9.1
|