2014-04-10 20:59:55 +00:00
|
|
|
From a03d3471b1741d354da03ff76313f057e5a0b51f Mon Sep 17 00:00:00 2001
|
2014-04-09 12:31:39 +00:00
|
|
|
From: Thinkofdeath <thethinkofdeath@gmail.com>
|
|
|
|
Date: Wed, 9 Apr 2014 13:29:57 +0100
|
|
|
|
Subject: [PATCH] Convert player heads async
|
|
|
|
|
|
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
|
|
|
|
index 90f32ed..6c2e905 100644
|
|
|
|
--- a/src/main/java/net/minecraft/server/Chunk.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/Chunk.java
|
|
|
|
@@ -513,6 +513,13 @@ public class Chunk {
|
|
|
|
if (tileentity != null) {
|
|
|
|
tileentity.u();
|
|
|
|
}
|
|
|
|
+
|
|
|
|
+ // Spigot start
|
|
|
|
+ if ( tileentity instanceof TileEntitySkull )
|
|
|
|
+ {
|
|
|
|
+ org.spigotmc.HeadConverter.convertHead( (TileEntitySkull) tileentity );
|
|
|
|
+ }
|
|
|
|
+ // Spigot end
|
|
|
|
}
|
|
|
|
|
|
|
|
this.n = true;
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
|
|
|
|
index fb262bc..4c086d3 100644
|
|
|
|
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
|
|
|
|
@@ -378,6 +378,12 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
|
|
|
|
TileEntity tileentity = TileEntity.c(nbttagcompound4);
|
|
|
|
|
|
|
|
if (tileentity != null) {
|
|
|
|
+ // Spigot start
|
|
|
|
+ if ( tileentity instanceof TileEntitySkull )
|
|
|
|
+ {
|
|
|
|
+ org.spigotmc.HeadConverter.convertHead( (TileEntitySkull) tileentity );
|
|
|
|
+ }
|
|
|
|
+ // Spigot end
|
|
|
|
chunk.a(tileentity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/ItemSkull.java b/src/main/java/net/minecraft/server/ItemSkull.java
|
|
|
|
index 6b2bf9b..5a74142 100644
|
|
|
|
--- a/src/main/java/net/minecraft/server/ItemSkull.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/ItemSkull.java
|
|
|
|
@@ -68,6 +68,7 @@ public class ItemSkull extends Item {
|
|
|
|
((TileEntitySkull) tileentity).setSkullType(itemstack.getData(), s);
|
|
|
|
((TileEntitySkull) tileentity).setRotation(i1);
|
|
|
|
((BlockSkull) Blocks.SKULL).a(world, i, j, k, (TileEntitySkull) tileentity);
|
|
|
|
+ org.spigotmc.HeadConverter.convertHead( (TileEntitySkull) tileentity ); // Spigot
|
|
|
|
}
|
|
|
|
|
|
|
|
--itemstack.count;
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/PacketPlayOutTileEntityData.java b/src/main/java/net/minecraft/server/PacketPlayOutTileEntityData.java
|
|
|
|
index 005f1fe..4780c53 100644
|
|
|
|
--- a/src/main/java/net/minecraft/server/PacketPlayOutTileEntityData.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/PacketPlayOutTileEntityData.java
|
|
|
|
@@ -1,5 +1,7 @@
|
|
|
|
package net.minecraft.server;
|
|
|
|
|
|
|
|
+import net.minecraft.util.com.mojang.authlib.GameProfile;
|
|
|
|
+
|
|
|
|
public class PacketPlayOutTileEntityData extends Packet {
|
|
|
|
|
|
|
|
private int a;
|
|
|
|
@@ -41,12 +43,14 @@ public class PacketPlayOutTileEntityData extends Packet {
|
|
|
|
packetdataserializer.writeShort(this.b);
|
|
|
|
packetdataserializer.writeInt(this.c);
|
|
|
|
packetdataserializer.writeByte((byte) this.d);
|
|
|
|
- if ( this.e.hasKey( "ExtraType" ) )
|
|
|
|
+ if ( this.e.hasKey( "ExtraType" ) && !this.e.hasKey( "Owner" ) )
|
|
|
|
{
|
|
|
|
NBTTagCompound profile = new NBTTagCompound();
|
|
|
|
profile.setString( "Name", this.e.getString( "ExtraType" ) );
|
|
|
|
profile.setString( "Id", "" );
|
|
|
|
this.e.set( "Owner", profile );
|
|
|
|
+ } else {
|
|
|
|
+ this.e.remove( "ExtraType" );
|
|
|
|
}
|
|
|
|
packetdataserializer.a(this.e);
|
|
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/TileEntitySkull.java b/src/main/java/net/minecraft/server/TileEntitySkull.java
|
|
|
|
index b241cfe..925e017 100644
|
|
|
|
--- a/src/main/java/net/minecraft/server/TileEntitySkull.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/TileEntitySkull.java
|
|
|
|
@@ -5,6 +5,7 @@ public class TileEntitySkull extends TileEntity {
|
|
|
|
private int a;
|
|
|
|
private int i;
|
|
|
|
private String j = "";
|
|
|
|
+ private NBTTagCompound owner = null;
|
|
|
|
|
|
|
|
public TileEntitySkull() {}
|
|
|
|
|
|
|
|
@@ -13,6 +14,7 @@ public class TileEntitySkull extends TileEntity {
|
|
|
|
nbttagcompound.setByte("SkullType", (byte) (this.a & 255));
|
|
|
|
nbttagcompound.setByte("Rot", (byte) (this.i & 255));
|
|
|
|
nbttagcompound.setString("ExtraType", this.j);
|
|
|
|
+ if ( owner != null ) nbttagcompound.set( "Owner", owner );
|
|
|
|
}
|
|
|
|
|
|
|
|
public void a(NBTTagCompound nbttagcompound) {
|
|
|
|
@@ -22,6 +24,10 @@ public class TileEntitySkull extends TileEntity {
|
|
|
|
if (nbttagcompound.hasKeyOfType("ExtraType", 8)) {
|
|
|
|
this.j = nbttagcompound.getString("ExtraType");
|
|
|
|
}
|
|
|
|
+ if ( nbttagcompound.hasKey( "Owner" ) )
|
|
|
|
+ {
|
|
|
|
+ owner = nbttagcompound.getCompound( "Owner" );
|
|
|
|
+ }
|
|
|
|
}
|
|
|
|
|
|
|
|
public Packet getUpdatePacket() {
|
|
|
|
diff --git a/src/main/java/org/spigotmc/HeadConverter.java b/src/main/java/org/spigotmc/HeadConverter.java
|
|
|
|
new file mode 100644
|
2014-04-10 20:59:55 +00:00
|
|
|
index 0000000..ad0454a
|
2014-04-09 12:31:39 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/src/main/java/org/spigotmc/HeadConverter.java
|
2014-04-10 20:59:55 +00:00
|
|
|
@@ -0,0 +1,195 @@
|
2014-04-09 12:31:39 +00:00
|
|
|
+package org.spigotmc;
|
|
|
|
+
|
|
|
|
+import com.google.common.base.Charsets;
|
|
|
|
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|
|
|
+import com.google.gson.JsonArray;
|
|
|
|
+import com.google.gson.JsonElement;
|
|
|
|
+import com.google.gson.JsonObject;
|
|
|
|
+import com.google.gson.JsonParser;
|
|
|
|
+import net.minecraft.server.EntityHuman;
|
|
|
|
+import net.minecraft.server.MinecraftServer;
|
2014-04-10 20:59:55 +00:00
|
|
|
+import net.minecraft.server.NBTBase;
|
2014-04-09 12:31:39 +00:00
|
|
|
+import net.minecraft.server.NBTTagCompound;
|
|
|
|
+import net.minecraft.server.NBTTagList;
|
|
|
|
+import net.minecraft.server.TileEntitySkull;
|
|
|
|
+import net.minecraft.util.com.mojang.authlib.GameProfile;
|
|
|
|
+import org.bukkit.Bukkit;
|
2014-04-10 16:45:21 +00:00
|
|
|
+import org.spigotmc.authlib.properties.Property;
|
2014-04-09 12:31:39 +00:00
|
|
|
+
|
|
|
|
+import java.io.IOException;
|
|
|
|
+import java.io.InputStreamReader;
|
|
|
|
+import java.io.OutputStream;
|
|
|
|
+import java.net.HttpURLConnection;
|
|
|
|
+import java.net.MalformedURLException;
|
|
|
|
+import java.net.URL;
|
2014-04-10 20:59:55 +00:00
|
|
|
+import java.util.Set;
|
|
|
|
+import java.util.UUID;
|
2014-04-09 12:31:39 +00:00
|
|
|
+import java.util.concurrent.Executor;
|
|
|
|
+import java.util.concurrent.Executors;
|
|
|
|
+
|
|
|
|
+public class HeadConverter
|
|
|
|
+{
|
|
|
|
+ private static final Executor executor = Executors.newFixedThreadPool( 3,
|
|
|
|
+ new ThreadFactoryBuilder()
|
|
|
|
+ .setNameFormat( "Head Conversion Thread - %1$d" )
|
|
|
|
+ .build()
|
|
|
|
+ );
|
2014-04-09 14:21:59 +00:00
|
|
|
+ private static boolean hasWarned = false;
|
2014-04-09 12:31:39 +00:00
|
|
|
+
|
|
|
|
+ public static void convertHead(final TileEntitySkull head)
|
|
|
|
+ {
|
|
|
|
+ if ( head.getSkullType() != 3 )
|
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ final int x = head.x;
|
|
|
|
+ final int y = head.y;
|
|
|
|
+ final int z = head.z;
|
|
|
|
+ final String name = head.getExtraType();
|
|
|
|
+ final NBTTagCompound tag = new NBTTagCompound();
|
|
|
|
+ head.b( tag );
|
2014-04-09 13:54:31 +00:00
|
|
|
+ if ( tag.hasKey( "Owner" ) && tag.getCompound( "Owner" ).hasKey( "Properties" ) )
|
|
|
|
+ {
|
2014-04-10 20:59:55 +00:00
|
|
|
+ // Validate the head
|
|
|
|
+ org.spigotmc.authlib.GameProfile profile = getProfile( tag.getCompound( "Owner" ) );
|
|
|
|
+ if ( MinecraftServer.getServer().newSessionService.getTextures( profile, false ).size() == 0 ) {
|
|
|
|
+ tag.remove( "Owner" );
|
|
|
|
+ head.a( tag );
|
|
|
|
+ } else
|
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
2014-04-09 12:31:39 +00:00
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ executor.execute( new Runnable()
|
|
|
|
+ {
|
|
|
|
+ @Override
|
|
|
|
+ public void run()
|
|
|
|
+ {
|
2014-04-09 13:54:31 +00:00
|
|
|
+ HttpURLConnection connection = null;
|
2014-04-09 12:31:39 +00:00
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ // Firstly convert name -> uuid
|
|
|
|
+ URL accountsAPI = new URL( "https://api.mojang.com/profiles/page/1" );
|
|
|
|
+
|
2014-04-09 13:54:31 +00:00
|
|
|
+ connection = (HttpURLConnection) accountsAPI.openConnection();
|
2014-04-09 12:31:39 +00:00
|
|
|
+ connection.setRequestProperty( "Content-Type", "application/json" );
|
|
|
|
+ connection.setRequestMethod( "POST" );
|
|
|
|
+ connection.setDoInput( true );
|
|
|
|
+ connection.setDoOutput( true );
|
|
|
|
+
|
|
|
|
+ OutputStream outputStream = connection.getOutputStream();
|
|
|
|
+ outputStream.write( ( "[{\"name\":\"" + name +
|
|
|
|
+ "\", \"agent\":\"minecraft\"}]" ).getBytes( Charsets.UTF_8 ) );
|
|
|
|
+ outputStream.flush();
|
|
|
|
+ outputStream.close();
|
|
|
|
+
|
2014-04-09 13:54:31 +00:00
|
|
|
+ InputStreamReader inputStreamReader = new InputStreamReader( connection.getInputStream() );
|
|
|
|
+ JsonObject response;
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ response = new JsonParser().parse( inputStreamReader )
|
|
|
|
+ .getAsJsonObject();
|
|
|
|
+ } finally
|
|
|
|
+ {
|
|
|
|
+ inputStreamReader.close();
|
|
|
|
+ }
|
2014-04-09 19:44:07 +00:00
|
|
|
+ if ( response.get( "size" ).getAsInt() != 1 ||
|
|
|
|
+ response.getAsJsonArray( "profiles" ).size() != 1 )
|
2014-04-09 12:31:39 +00:00
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ String uuid = response.getAsJsonArray( "profiles" )
|
|
|
|
+ .get( 0 ).getAsJsonObject()
|
|
|
|
+ .get( "id" ).getAsString();
|
2014-04-10 20:59:55 +00:00
|
|
|
+ String correctedName = response.getAsJsonArray( "profiles" )
|
|
|
|
+ .get( 0 ).getAsJsonObject()
|
|
|
|
+ .get( "name" ).getAsString();
|
2014-04-09 12:31:39 +00:00
|
|
|
+
|
|
|
|
+ NBTTagCompound owner = new NBTTagCompound();
|
2014-04-10 20:59:55 +00:00
|
|
|
+ GameProfile gameProfile = new GameProfile( uuid, correctedName );
|
|
|
|
+ owner.setString( "Name", correctedName );
|
2014-04-09 12:31:39 +00:00
|
|
|
+ owner.setString( "Id", EntityHuman.a( gameProfile ).toString() );
|
|
|
|
+
|
|
|
|
+ NBTTagCompound properties = new NBTTagCompound();
|
|
|
|
+
|
|
|
|
+ // Now to lookup the textures
|
2014-04-10 16:45:21 +00:00
|
|
|
+ org.spigotmc.authlib.GameProfile newStyleProfile = new org.spigotmc.authlib.GameProfile(
|
|
|
|
+ EntityHuman.a( gameProfile ),
|
|
|
|
+ gameProfile.getName() );
|
|
|
|
+ MinecraftServer.getServer().newSessionService.fillProfileProperties( newStyleProfile );
|
2014-04-09 12:31:39 +00:00
|
|
|
+
|
2014-04-10 20:12:49 +00:00
|
|
|
+ if ( newStyleProfile.getProperties().size() < 1)
|
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
2014-04-09 12:31:39 +00:00
|
|
|
+
|
2014-04-10 16:45:21 +00:00
|
|
|
+ for ( String key : newStyleProfile.getProperties().keys() )
|
2014-04-09 12:31:39 +00:00
|
|
|
+ {
|
|
|
|
+ NBTTagList propList = new NBTTagList();
|
2014-04-10 16:45:21 +00:00
|
|
|
+ for ( Property prop : newStyleProfile.getProperties().get( key ) )
|
|
|
|
+ {
|
|
|
|
+ NBTTagCompound nprop = new NBTTagCompound();
|
2014-04-10 20:23:07 +00:00
|
|
|
+ nprop.setString( "Signature", prop.getSignature() );
|
|
|
|
+ nprop.setString( "Value", prop.getValue() );
|
2014-04-10 16:45:21 +00:00
|
|
|
+ propList.add( nprop );
|
|
|
|
+ }
|
|
|
|
+ properties.set( key, propList );
|
2014-04-09 12:31:39 +00:00
|
|
|
+ }
|
2014-04-10 16:45:21 +00:00
|
|
|
+
|
2014-04-09 12:31:39 +00:00
|
|
|
+ owner.set( "Properties", properties );
|
|
|
|
+ tag.set( "Owner", owner );
|
|
|
|
+
|
|
|
|
+ // Update the tile entity
|
|
|
|
+ MinecraftServer.getServer().processQueue.add( new Runnable()
|
|
|
|
+ {
|
|
|
|
+ @Override
|
|
|
|
+ public void run()
|
|
|
|
+ {
|
|
|
|
+ head.a( tag );
|
|
|
|
+ // Send the updated version
|
|
|
|
+ MinecraftServer.getServer().getPlayerList().sendPacketNearby(
|
|
|
|
+ x, y, z, head.getWorld().spigotConfig.viewDistance * 16, head.getWorld().worldData.j(),
|
|
|
|
+ head.getUpdatePacket() );
|
|
|
|
+ }
|
|
|
|
+ } );
|
|
|
|
+
|
|
|
|
+ } catch ( MalformedURLException e )
|
|
|
|
+ {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ } catch ( IOException e )
|
|
|
|
+ {
|
2014-04-09 14:21:59 +00:00
|
|
|
+ if (!hasWarned)
|
|
|
|
+ {
|
|
|
|
+ hasWarned = true;
|
|
|
|
+ Bukkit.getLogger().warning( "Error connecting to Mojang servers, cannot convert player heads" );
|
|
|
|
+ }
|
2014-04-09 13:54:31 +00:00
|
|
|
+ } finally
|
|
|
|
+ {
|
|
|
|
+ if ( connection != null )
|
|
|
|
+ {
|
|
|
|
+ connection.disconnect();
|
|
|
|
+ }
|
2014-04-09 12:31:39 +00:00
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } );
|
|
|
|
+ }
|
2014-04-10 20:59:55 +00:00
|
|
|
+
|
|
|
|
+ private static org.spigotmc.authlib.GameProfile getProfile(NBTTagCompound owner)
|
|
|
|
+ {
|
|
|
|
+ org.spigotmc.authlib.GameProfile profile = new org.spigotmc.authlib.GameProfile(
|
|
|
|
+ UUID.fromString( owner.getString( "Id" ) ), owner.getString( "Name" ) );
|
|
|
|
+
|
|
|
|
+ NBTTagCompound properties = owner.getCompound( "Properties" );
|
|
|
|
+ for (String key : (Set<String>) properties.c())
|
|
|
|
+ {
|
|
|
|
+ NBTTagList props = properties.getList( key, 10 );
|
|
|
|
+ for (int i = 0; i < props.size(); i++) {
|
|
|
|
+ NBTTagCompound prop = props.get( i );
|
|
|
|
+ profile.getProperties().put( key, new Property( key, prop.getString( "Value" ), prop.getString( "Signature" ) ) );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return profile;
|
|
|
|
+ }
|
2014-04-09 12:31:39 +00:00
|
|
|
+}
|
|
|
|
--
|
|
|
|
1.8.5.2.msysgit.0
|
|
|
|
|