785 lines
28 KiB
Java
785 lines
28 KiB
Java
|
package eu.univento.core.api;
|
||
|
|
||
|
import com.google.gson.Gson;
|
||
|
import com.google.gson.GsonBuilder;
|
||
|
import com.google.gson.JsonDeserializationContext;
|
||
|
import com.google.gson.JsonDeserializer;
|
||
|
import com.google.gson.JsonElement;
|
||
|
import com.google.gson.JsonObject;
|
||
|
import com.google.gson.JsonParseException;
|
||
|
import com.google.gson.JsonParser;
|
||
|
import com.google.gson.JsonPrimitive;
|
||
|
import com.google.gson.JsonSerializationContext;
|
||
|
import com.google.gson.JsonSerializer;
|
||
|
import com.mojang.authlib.GameProfile;
|
||
|
import com.mojang.authlib.properties.Property;
|
||
|
import com.mojang.authlib.properties.PropertyMap;
|
||
|
import com.mojang.authlib.properties.PropertyMap.Serializer;
|
||
|
import com.mojang.util.UUIDTypeAdapter;
|
||
|
import io.netty.channel.Channel;
|
||
|
import io.netty.channel.ChannelHandlerContext;
|
||
|
import io.netty.channel.ChannelPipeline;
|
||
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||
|
import java.io.BufferedReader;
|
||
|
import java.io.IOException;
|
||
|
import java.io.InputStreamReader;
|
||
|
import java.lang.reflect.Field;
|
||
|
import java.lang.reflect.Type;
|
||
|
import java.net.HttpURLConnection;
|
||
|
import java.net.URL;
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.Collection;
|
||
|
import java.util.HashMap;
|
||
|
import java.util.Iterator;
|
||
|
import java.util.List;
|
||
|
import java.util.Map;
|
||
|
import java.util.Map.Entry;
|
||
|
import java.util.Random;
|
||
|
import java.util.UUID;
|
||
|
import java.util.concurrent.ExecutorService;
|
||
|
import java.util.concurrent.Executors;
|
||
|
import net.md_5.bungee.api.ChatColor;
|
||
|
import net.minecraft.server.v1_8_R3.DataWatcher;
|
||
|
import net.minecraft.server.v1_8_R3.EntityPlayer;
|
||
|
import net.minecraft.server.v1_8_R3.NetworkManager;
|
||
|
import net.minecraft.server.v1_8_R3.Packet;
|
||
|
import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
|
||
|
import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity.EnumEntityUseAction;
|
||
|
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
|
||
|
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityEquipment;
|
||
|
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityTeleport;
|
||
|
import net.minecraft.server.v1_8_R3.PacketPlayOutNamedEntitySpawn;
|
||
|
import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo;
|
||
|
import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;
|
||
|
import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo.PlayerInfoData;
|
||
|
import net.minecraft.server.v1_8_R3.PlayerConnection;
|
||
|
import net.minecraft.server.v1_8_R3.WorldSettings;
|
||
|
import net.minecraft.server.v1_8_R3.WorldSettings.EnumGamemode;
|
||
|
import org.bukkit.Bukkit;
|
||
|
import org.bukkit.Location;
|
||
|
import org.bukkit.Material;
|
||
|
import org.bukkit.block.Block;
|
||
|
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
|
||
|
import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack;
|
||
|
import org.bukkit.craftbukkit.v1_8_R3.util.CraftChatMessage;
|
||
|
import org.bukkit.entity.Player;
|
||
|
import org.bukkit.event.HandlerList;
|
||
|
import org.bukkit.event.player.PlayerEvent;
|
||
|
import org.bukkit.inventory.ItemStack;
|
||
|
import org.bukkit.plugin.PluginManager;
|
||
|
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
|
||
|
|
||
|
public class NPC
|
||
|
{
|
||
|
private static Map<Integer, NPC> npcs = new HashMap<Integer, NPC>();
|
||
|
private static Field channelField;
|
||
|
private static Field idField;
|
||
|
private DataWatcher watcher;
|
||
|
private GameProfile profile;
|
||
|
private Material chestplate;
|
||
|
private boolean hideTablist;
|
||
|
private Material leggings;
|
||
|
private Location location;
|
||
|
private String skinName;
|
||
|
private Material inHand;
|
||
|
private Material helmet;
|
||
|
private Material boots;
|
||
|
private String tablist;
|
||
|
private int entityID;
|
||
|
private String name;
|
||
|
|
||
|
static
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
idField = PacketPlayInUseEntity.class.getDeclaredField("a");
|
||
|
idField.setAccessible(true);
|
||
|
} catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
for (Field field : NetworkManager.class.getDeclaredFields())
|
||
|
if (field.getType().isAssignableFrom(Channel.class)) {
|
||
|
channelField = field;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public NPC(String skinName, String name, String tablist, int entityID, Location location, Material inHand, boolean hideTablist)
|
||
|
{
|
||
|
this.location = location;
|
||
|
this.tablist = ChatColor.translateAlternateColorCodes('&', tablist);
|
||
|
this.name = ChatColor.translateAlternateColorCodes('&', name);
|
||
|
this.entityID = entityID;
|
||
|
this.inHand = inHand;
|
||
|
this.skinName = skinName;
|
||
|
this.watcher = new DataWatcher(null);
|
||
|
this.hideTablist = hideTablist;
|
||
|
this.watcher.a(6, Float.valueOf(20.0F));
|
||
|
}
|
||
|
|
||
|
public NPC(String name, Location location, boolean hideTablist)
|
||
|
{
|
||
|
this(null, name, name, new Random().nextInt(10000), location,
|
||
|
Material.AIR, hideTablist);
|
||
|
}
|
||
|
|
||
|
public NPC(String skinName, String name, Location location, boolean hideTablist)
|
||
|
{
|
||
|
this(skinName, name, name, new Random().nextInt(10000), location,
|
||
|
Material.AIR, hideTablist);
|
||
|
}
|
||
|
|
||
|
public NPC(String name, Location location, Material inHand, boolean hideTablist)
|
||
|
{
|
||
|
this(null, name, name, new Random().nextInt(10000), location, inHand,
|
||
|
hideTablist);
|
||
|
}
|
||
|
|
||
|
public NPC(String name, String tablist, Location location, Material inHand, boolean hideTablist)
|
||
|
{
|
||
|
this(null, name, tablist, new Random().nextInt(10000), location,
|
||
|
inHand, hideTablist);
|
||
|
}
|
||
|
|
||
|
@SuppressWarnings("deprecation")
|
||
|
public void spawn()
|
||
|
{
|
||
|
try {
|
||
|
PacketPlayOutNamedEntitySpawn packet = new PacketPlayOutNamedEntitySpawn();
|
||
|
addToTablist();
|
||
|
setValue(packet, "a", Integer.valueOf(this.entityID));
|
||
|
setValue(packet, "b", this.profile.getId());
|
||
|
setValue(packet, "c", Integer.valueOf(toFixedPoint(this.location.getX())));
|
||
|
setValue(packet, "d", Integer.valueOf(toFixedPoint(this.location.getY())));
|
||
|
setValue(packet, "e", Integer.valueOf(toFixedPoint(this.location.getZ())));
|
||
|
setValue(packet, "f", Byte.valueOf(toPackedByte(this.location.getYaw())));
|
||
|
setValue(packet, "g", Byte.valueOf(toPackedByte(this.location.getPitch())));
|
||
|
setValue(packet, "h", Integer.valueOf(this.inHand == null ? 0 : this.inHand.getId()));
|
||
|
setValue(packet, "i", this.watcher);
|
||
|
for (Player online : Bukkit.getOnlinePlayers()) {
|
||
|
((CraftPlayer)online).getHandle().playerConnection
|
||
|
.sendPacket(packet);
|
||
|
}
|
||
|
npcs.put(Integer.valueOf(this.entityID), this);
|
||
|
if (this.hideTablist)
|
||
|
removeFromTablist();
|
||
|
} catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void despawn() {
|
||
|
PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(new int[] {
|
||
|
this.entityID });
|
||
|
removeFromTablist();
|
||
|
for (Player online : Bukkit.getOnlinePlayers()) {
|
||
|
((CraftPlayer)online).getHandle().playerConnection
|
||
|
.sendPacket(packet);
|
||
|
}
|
||
|
npcs.remove(Integer.valueOf(this.entityID));
|
||
|
}
|
||
|
|
||
|
public void changePlayerlistName(String name) {
|
||
|
try {
|
||
|
PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(
|
||
|
PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_DISPLAY_NAME, new EntityPlayer[0]);
|
||
|
PacketPlayOutPlayerInfo tmp20_19 = packet; tmp20_19.getClass(); PacketPlayOutPlayerInfo.PlayerInfoData data = new PacketPlayOutPlayerInfo.PlayerInfoData(tmp20_19,
|
||
|
this.profile, 0, WorldSettings.EnumGamemode.NOT_SET,
|
||
|
CraftChatMessage.fromString(name)[0]);
|
||
|
|
||
|
List players = (List)
|
||
|
getValue(packet, "b");
|
||
|
players.add(data);
|
||
|
setValue(packet, "b", players);
|
||
|
this.tablist = name;
|
||
|
for (Player online : Bukkit.getOnlinePlayers())
|
||
|
((CraftPlayer)online).getHandle().playerConnection
|
||
|
.sendPacket(packet);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void addToTablist() {
|
||
|
try {
|
||
|
PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
|
||
|
GameProfile profile = this.profile = getProfile();
|
||
|
PacketPlayOutPlayerInfo tmp23_22 = packet; tmp23_22.getClass(); PacketPlayOutPlayerInfo.PlayerInfoData data = new PacketPlayOutPlayerInfo.PlayerInfoData(tmp23_22,
|
||
|
profile, 1, WorldSettings.EnumGamemode.NOT_SET,
|
||
|
org.bukkit.craftbukkit.v1_8_R3.util.CraftChatMessage.fromString(this.tablist)[0]);
|
||
|
|
||
|
List players = (List)getValue(
|
||
|
packet, "b");
|
||
|
players.add(data);
|
||
|
setValue(packet, "a",
|
||
|
PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER);
|
||
|
setValue(packet, "b", players);
|
||
|
for (Player online : Bukkit.getOnlinePlayers())
|
||
|
((CraftPlayer)online).getHandle().playerConnection
|
||
|
.sendPacket(packet);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void removeFromTablist() {
|
||
|
try {
|
||
|
PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(
|
||
|
PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[0]);
|
||
|
PacketPlayOutPlayerInfo tmp20_19 = packet; tmp20_19.getClass(); PacketPlayOutPlayerInfo.PlayerInfoData data = new PacketPlayOutPlayerInfo.PlayerInfoData(tmp20_19,
|
||
|
this.profile, -1, null, null);
|
||
|
|
||
|
List players = (List)
|
||
|
getValue(packet, "b");
|
||
|
players.add(data);
|
||
|
setValue(packet, "b", players);
|
||
|
for (Player online : Bukkit.getOnlinePlayers())
|
||
|
((CraftPlayer)online).getHandle().playerConnection
|
||
|
.sendPacket(packet);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void teleport(Location location) {
|
||
|
try {
|
||
|
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
|
||
|
setValue(packet, "a", Integer.valueOf(this.entityID));
|
||
|
setValue(packet, "b", Integer.valueOf(toFixedPoint(location.getX())));
|
||
|
setValue(packet, "c", Integer.valueOf(toFixedPoint(location.getY())));
|
||
|
setValue(packet, "d", Integer.valueOf(toFixedPoint(location.getZ())));
|
||
|
setValue(packet, "e", Byte.valueOf(toPackedByte(location.getYaw())));
|
||
|
setValue(packet, "f", Byte.valueOf(toPackedByte(location.getPitch())));
|
||
|
setValue(packet, "g",
|
||
|
Boolean.valueOf(this.location.getBlock().getType() != Material.AIR));
|
||
|
this.location = location;
|
||
|
for (Player online : Bukkit.getOnlinePlayers())
|
||
|
((CraftPlayer)online).getHandle().playerConnection
|
||
|
.sendPacket(packet);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void setItemInHand(Material material) {
|
||
|
try {
|
||
|
PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment();
|
||
|
setValue(packet, "a", Integer.valueOf(this.entityID));
|
||
|
setValue(packet, "b", Integer.valueOf(0));
|
||
|
setValue(
|
||
|
packet,
|
||
|
"c",
|
||
|
(material == Material.AIR) || (material == null) ?
|
||
|
CraftItemStack.asNMSCopy(new ItemStack(Material.AIR)) :
|
||
|
CraftItemStack.asNMSCopy(new ItemStack(material)));
|
||
|
this.inHand = material;
|
||
|
for (Player online : Bukkit.getOnlinePlayers())
|
||
|
((CraftPlayer)online).getHandle().playerConnection
|
||
|
.sendPacket(packet);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Material getItemInHand() {
|
||
|
return this.inHand;
|
||
|
}
|
||
|
|
||
|
public void setHelmet(Material material) {
|
||
|
try {
|
||
|
PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment();
|
||
|
setValue(packet, "a", Integer.valueOf(this.entityID));
|
||
|
setValue(packet, "b", Integer.valueOf(4));
|
||
|
setValue(
|
||
|
packet,
|
||
|
"c",
|
||
|
(material == Material.AIR) || (material == null) ?
|
||
|
CraftItemStack.asNMSCopy(new ItemStack(Material.AIR)) :
|
||
|
CraftItemStack.asNMSCopy(new ItemStack(material)));
|
||
|
this.helmet = material;
|
||
|
for (Player online : Bukkit.getOnlinePlayers())
|
||
|
((CraftPlayer)online).getHandle().playerConnection
|
||
|
.sendPacket(packet);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Material getHelmet() {
|
||
|
return this.helmet;
|
||
|
}
|
||
|
|
||
|
public void setChestplate(Material material) {
|
||
|
try {
|
||
|
PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment();
|
||
|
setValue(packet, "a", Integer.valueOf(this.entityID));
|
||
|
setValue(packet, "b", Integer.valueOf(3));
|
||
|
setValue(
|
||
|
packet,
|
||
|
"c",
|
||
|
(material == Material.AIR) || (material == null) ?
|
||
|
CraftItemStack.asNMSCopy(new ItemStack(Material.AIR)) :
|
||
|
CraftItemStack.asNMSCopy(new ItemStack(material)));
|
||
|
this.chestplate = material;
|
||
|
for (Player online : Bukkit.getOnlinePlayers())
|
||
|
((CraftPlayer)online).getHandle().playerConnection
|
||
|
.sendPacket(packet);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Material getChestplate() {
|
||
|
return this.chestplate;
|
||
|
}
|
||
|
|
||
|
public void setLeggings(Material material) {
|
||
|
try {
|
||
|
PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment();
|
||
|
setValue(packet, "a", Integer.valueOf(this.entityID));
|
||
|
setValue(packet, "b", Integer.valueOf(2));
|
||
|
setValue(
|
||
|
packet,
|
||
|
"c",
|
||
|
(material == Material.AIR) || (material == null) ?
|
||
|
CraftItemStack.asNMSCopy(new ItemStack(Material.AIR)) :
|
||
|
CraftItemStack.asNMSCopy(new ItemStack(material)));
|
||
|
this.leggings = material;
|
||
|
for (Player online : Bukkit.getOnlinePlayers())
|
||
|
((CraftPlayer)online).getHandle().playerConnection
|
||
|
.sendPacket(packet);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Material getLeggings() {
|
||
|
return this.leggings;
|
||
|
}
|
||
|
|
||
|
public void setBoots(Material material) {
|
||
|
try {
|
||
|
PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment();
|
||
|
setValue(packet, "a", Integer.valueOf(this.entityID));
|
||
|
setValue(packet, "b", Integer.valueOf(1));
|
||
|
setValue(
|
||
|
packet,
|
||
|
"c",
|
||
|
(material == Material.AIR) || (material == null) ?
|
||
|
CraftItemStack.asNMSCopy(new ItemStack(Material.AIR)) :
|
||
|
CraftItemStack.asNMSCopy(new ItemStack(material)));
|
||
|
this.boots = material;
|
||
|
for (Player online : Bukkit.getOnlinePlayers())
|
||
|
((CraftPlayer)online).getHandle().playerConnection
|
||
|
.sendPacket(packet);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Material getBoots() {
|
||
|
return this.boots;
|
||
|
}
|
||
|
|
||
|
public int getEntityID() {
|
||
|
return this.entityID;
|
||
|
}
|
||
|
|
||
|
public UUID getUUID() {
|
||
|
return this.profile.getId();
|
||
|
}
|
||
|
|
||
|
public Location getLocation() {
|
||
|
return this.location;
|
||
|
}
|
||
|
|
||
|
public String getName() {
|
||
|
return this.name;
|
||
|
}
|
||
|
|
||
|
public String getPlayerlistName() {
|
||
|
return this.tablist;
|
||
|
}
|
||
|
|
||
|
private void setValue(Object instance, String field, Object value) throws Exception
|
||
|
{
|
||
|
Field f = instance.getClass().getDeclaredField(field);
|
||
|
f.setAccessible(true);
|
||
|
f.set(instance, value);
|
||
|
}
|
||
|
|
||
|
private Object getValue(Object instance, String field) throws Exception {
|
||
|
Field f = instance.getClass().getDeclaredField(field);
|
||
|
f.setAccessible(true);
|
||
|
return f.get(instance);
|
||
|
}
|
||
|
|
||
|
private int toFixedPoint(double d) {
|
||
|
return (int)(d * 32.0D);
|
||
|
}
|
||
|
|
||
|
private byte toPackedByte(float f) {
|
||
|
return (byte)(int)(f * 256.0F / 360.0F);
|
||
|
}
|
||
|
|
||
|
private GameProfile getProfile() {
|
||
|
try {
|
||
|
GameProfile profile = GameProfileBuilder.fetch(
|
||
|
UUIDFetcher.getUUID(ChatColor.stripColor(this.name)));
|
||
|
Field name = profile.getClass().getDeclaredField("name");
|
||
|
name.setAccessible(true);
|
||
|
name.set(profile, this.name);
|
||
|
return profile; } catch (Exception e) {
|
||
|
}
|
||
|
return getFakeProfile();
|
||
|
}
|
||
|
|
||
|
private GameProfile getFakeProfile()
|
||
|
{
|
||
|
try {
|
||
|
GameProfile profile = GameProfileBuilder.fetch(
|
||
|
UUIDFetcher.getUUID(ChatColor.stripColor(this.skinName)));
|
||
|
Field name = profile.getClass().getDeclaredField("name");
|
||
|
name.setAccessible(true);
|
||
|
name.set(profile, this.name);
|
||
|
return profile; } catch (Exception e) {
|
||
|
}
|
||
|
return new GameProfile(UUID.randomUUID(), this.name);
|
||
|
}
|
||
|
|
||
|
public static void injectNetty(Player player)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
Channel channel = (Channel)channelField.get(((CraftPlayer)player)
|
||
|
.getHandle().playerConnection.networkManager);
|
||
|
if (channel != null)
|
||
|
channel.pipeline().addAfter("decoder", "npc_interact",
|
||
|
new MessageToMessageDecoder(player)
|
||
|
{
|
||
|
protected void decode(ChannelHandlerContext chc, Packet packet, List<Object> out)
|
||
|
throws Exception
|
||
|
{
|
||
|
if ((packet instanceof PacketPlayInUseEntity)) {
|
||
|
PacketPlayInUseEntity usePacket = (PacketPlayInUseEntity)packet;
|
||
|
if (usePacket.a() == PacketPlayInUseEntity.EnumEntityUseAction.INTERACT) {
|
||
|
int entityId =
|
||
|
((Integer)NPC.idField
|
||
|
.get(usePacket)).intValue();
|
||
|
if (NPC.npcs.containsKey(Integer.valueOf(entityId))) {
|
||
|
Bukkit.getPluginManager()
|
||
|
.callEvent(
|
||
|
new NPC.PlayerInteractNPCEvent(
|
||
|
NPC.this,
|
||
|
(NPC)NPC.npcs.get(Integer.valueOf(entityId))));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
out.add(packet);
|
||
|
} } );
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void ejectNetty(Player player) {
|
||
|
try {
|
||
|
Channel channel = (Channel)channelField.get(((CraftPlayer)player)
|
||
|
.getHandle().playerConnection.networkManager);
|
||
|
if ((channel != null) &&
|
||
|
(channel.pipeline().get("npc_interact") != null))
|
||
|
channel.pipeline().remove("npc_interact");
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static class GameProfileBuilder
|
||
|
{
|
||
|
private static final String SERVICE_URL = "https://sessionserver.mojang.com/session/minecraft/profile/%s?unsigned=false";
|
||
|
private static final String JSON_SKIN = "{\"timestamp\":%d,\"profileId\":\"%s\",\"profileName\":\"%s\",\"isPublic\":true,\"textures\":{\"SKIN\":{\"url\":\"%s\"}}}";
|
||
|
private static final String JSON_CAPE = "{\"timestamp\":%d,\"profileId\":\"%s\",\"profileName\":\"%s\",\"isPublic\":true,\"textures\":{\"SKIN\":{\"url\":\"%s\"},\"CAPE\":{\"url\":\"%s\"}}}";
|
||
|
private static Gson gson = new GsonBuilder()
|
||
|
.disableHtmlEscaping()
|
||
|
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter())
|
||
|
.registerTypeAdapter(GameProfile.class,
|
||
|
new GameProfileSerializer(null))
|
||
|
.registerTypeAdapter(PropertyMap.class,
|
||
|
new PropertyMap.Serializer()).create();
|
||
|
private static HashMap<UUID, CachedProfile> cache = new HashMap();
|
||
|
private static long cacheTime = -1L;
|
||
|
|
||
|
public static GameProfile fetch(UUID uuid)
|
||
|
throws IOException
|
||
|
{
|
||
|
return fetch(uuid, false);
|
||
|
}
|
||
|
|
||
|
public static GameProfile fetch(UUID uuid, boolean forceNew)
|
||
|
throws IOException
|
||
|
{
|
||
|
if ((!forceNew) && (cache.containsKey(uuid)) &&
|
||
|
(((CachedProfile)cache.get(uuid)).isValid())) {
|
||
|
return ((CachedProfile)cache.get(uuid)).profile;
|
||
|
}
|
||
|
HttpURLConnection connection = (HttpURLConnection)new URL(
|
||
|
String.format("https://sessionserver.mojang.com/session/minecraft/profile/%s?unsigned=false", new Object[] {
|
||
|
UUIDTypeAdapter.fromUUID(uuid) }))
|
||
|
.openConnection();
|
||
|
connection.setReadTimeout(5000);
|
||
|
if (connection.getResponseCode() == 200) {
|
||
|
String json = new BufferedReader(
|
||
|
new InputStreamReader(connection.getInputStream())).readLine();
|
||
|
GameProfile result = (GameProfile)gson.fromJson(json, GameProfile.class);
|
||
|
cache.put(uuid, new CachedProfile(result));
|
||
|
return result;
|
||
|
}
|
||
|
if ((!forceNew) && (cache.containsKey(uuid))) {
|
||
|
return ((CachedProfile)cache.get(uuid)).profile;
|
||
|
}
|
||
|
JsonObject error = (JsonObject)new JsonParser()
|
||
|
.parse(new BufferedReader(
|
||
|
new InputStreamReader(connection.getErrorStream())).readLine());
|
||
|
throw new IOException(error.get("error").getAsString() +
|
||
|
": " + error.get("errorMessage").getAsString());
|
||
|
}
|
||
|
|
||
|
public static GameProfile getProfile(UUID uuid, String name, String skin)
|
||
|
{
|
||
|
return getProfile(uuid, name, skin, null);
|
||
|
}
|
||
|
|
||
|
public static GameProfile getProfile(UUID uuid, String name, String skinUrl, String capeUrl)
|
||
|
{
|
||
|
GameProfile profile = new GameProfile(uuid, name);
|
||
|
boolean cape = (capeUrl != null) && (!capeUrl.isEmpty());
|
||
|
List args = new ArrayList();
|
||
|
args.add(Long.valueOf(System.currentTimeMillis()));
|
||
|
args.add(UUIDTypeAdapter.fromUUID(uuid));
|
||
|
args.add(name);
|
||
|
args.add(skinUrl);
|
||
|
if (cape)
|
||
|
args.add(capeUrl);
|
||
|
profile.getProperties().put(
|
||
|
"textures",
|
||
|
new Property("textures", Base64Coder.encodeString(
|
||
|
String.format(cape ? "{\"timestamp\":%d,\"profileId\":\"%s\",\"profileName\":\"%s\",\"isPublic\":true,\"textures\":{\"SKIN\":{\"url\":\"%s\"},\"CAPE\":{\"url\":\"%s\"}}}" : "{\"timestamp\":%d,\"profileId\":\"%s\",\"profileName\":\"%s\",\"isPublic\":true,\"textures\":{\"SKIN\":{\"url\":\"%s\"}}}",
|
||
|
args.toArray(new Object[args.size()])))));
|
||
|
return profile;
|
||
|
}
|
||
|
|
||
|
public static void setCacheTime(long time)
|
||
|
{
|
||
|
cacheTime = time;
|
||
|
}
|
||
|
private static class CachedProfile {
|
||
|
private long timestamp = System.currentTimeMillis();
|
||
|
private GameProfile profile;
|
||
|
|
||
|
public CachedProfile(GameProfile profile) {
|
||
|
this.profile = profile;
|
||
|
}
|
||
|
|
||
|
public boolean isValid() {
|
||
|
return (NPC.GameProfileBuilder.cacheTime < 0L) || (
|
||
|
System.currentTimeMillis() - this.timestamp < NPC.GameProfileBuilder.cacheTime);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static class GameProfileSerializer
|
||
|
implements JsonSerializer<GameProfile>, JsonDeserializer<GameProfile>
|
||
|
{
|
||
|
public GameProfile deserialize(JsonElement json, Type type, JsonDeserializationContext context)
|
||
|
throws JsonParseException
|
||
|
{
|
||
|
JsonObject object = (JsonObject)json;
|
||
|
UUID id = object.has("id") ? (UUID)context.deserialize(
|
||
|
object.get("id"), UUID.class) :
|
||
|
null;
|
||
|
String name = object.has("name") ? object.getAsJsonPrimitive(
|
||
|
"name").getAsString() : null;
|
||
|
GameProfile profile = new GameProfile(id, name);
|
||
|
if (object.has("properties"))
|
||
|
{
|
||
|
Iterator localIterator = ((PropertyMap)context
|
||
|
.deserialize(object.get("properties"),
|
||
|
PropertyMap.class)).entries().iterator();
|
||
|
|
||
|
while (localIterator.hasNext())
|
||
|
{
|
||
|
Map.Entry prop = (Map.Entry)localIterator.next();
|
||
|
profile.getProperties().put((String)prop.getKey(),
|
||
|
(Property)prop.getValue());
|
||
|
}
|
||
|
}
|
||
|
return profile;
|
||
|
}
|
||
|
|
||
|
public JsonElement serialize(GameProfile profile, Type type, JsonSerializationContext context)
|
||
|
{
|
||
|
JsonObject result = new JsonObject();
|
||
|
if (profile.getId() != null)
|
||
|
result.add("id", context.serialize(profile.getId()));
|
||
|
if (profile.getName() != null)
|
||
|
result.addProperty("name", profile.getName());
|
||
|
if (!profile.getProperties().isEmpty())
|
||
|
result.add("properties",
|
||
|
context.serialize(profile.getProperties()));
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static class PlayerInteractNPCEvent extends PlayerEvent
|
||
|
{
|
||
|
public static HandlerList handlers = new HandlerList();
|
||
|
private NPC npc;
|
||
|
|
||
|
public PlayerInteractNPCEvent(Player who, NPC npc)
|
||
|
{
|
||
|
super();
|
||
|
this.npc = npc;
|
||
|
}
|
||
|
|
||
|
public NPC getNpc() {
|
||
|
return this.npc;
|
||
|
}
|
||
|
|
||
|
public HandlerList getHandlers()
|
||
|
{
|
||
|
return handlers;
|
||
|
}
|
||
|
|
||
|
public static HandlerList getHandlerList() {
|
||
|
return handlers;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static class UUIDFetcher
|
||
|
{
|
||
|
public static final long FEBRUARY_2015 = 1422748800000L;
|
||
|
private static Gson gson = new GsonBuilder().registerTypeAdapter(
|
||
|
UUID.class, new UUIDTypeAdapter()).create();
|
||
|
private static final String UUID_URL = "https://api.mojang.com/users/profiles/minecraft/%s?at=%d";
|
||
|
private static final String NAME_URL = "https://api.mojang.com/user/profiles/%s/names";
|
||
|
private static Map<String, UUID> uuidCache = new HashMap();
|
||
|
private static Map<UUID, String> nameCache = new HashMap();
|
||
|
private static ExecutorService pool = Executors.newCachedThreadPool();
|
||
|
private String name;
|
||
|
private UUID id;
|
||
|
|
||
|
public static void getUUID(String name, Consumer<UUID> action)
|
||
|
{
|
||
|
pool.execute(new Acceptor(action, name)
|
||
|
{
|
||
|
public UUID getValue() {
|
||
|
return NPC.UUIDFetcher.getUUID(this.val$name);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public static UUID getUUID(String name)
|
||
|
{
|
||
|
return getUUIDAt(name, System.currentTimeMillis());
|
||
|
}
|
||
|
|
||
|
public static void getUUIDAt(String name, long timestamp, Consumer<UUID> action)
|
||
|
{
|
||
|
pool.execute(new Acceptor(action, name, timestamp)
|
||
|
{
|
||
|
public UUID getValue() {
|
||
|
return NPC.UUIDFetcher.getUUIDAt(this.val$name, this.val$timestamp);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public static UUID getUUIDAt(String name, long timestamp)
|
||
|
{
|
||
|
name = name.toLowerCase();
|
||
|
if (uuidCache.containsKey(name))
|
||
|
return (UUID)uuidCache.get(name);
|
||
|
try
|
||
|
{
|
||
|
HttpURLConnection connection = (HttpURLConnection)new URL(
|
||
|
String.format("https://api.mojang.com/users/profiles/minecraft/%s?at=%d", new Object[] { name, Long.valueOf(timestamp / 1000L) }))
|
||
|
.openConnection();
|
||
|
connection.setReadTimeout(5000);
|
||
|
UUIDFetcher data = (UUIDFetcher)gson.fromJson(
|
||
|
new BufferedReader(new InputStreamReader(connection.getInputStream())),
|
||
|
UUIDFetcher.class);
|
||
|
uuidCache.put(name, data.id);
|
||
|
nameCache.put(data.id, data.name);
|
||
|
return data.id;
|
||
|
} catch (Exception localException) {
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public static void getName(UUID uuid, Consumer<String> action)
|
||
|
{
|
||
|
pool.execute(new Acceptor(action, uuid)
|
||
|
{
|
||
|
public String getValue() {
|
||
|
return NPC.UUIDFetcher.getName(this.val$uuid);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public static String getName(UUID uuid)
|
||
|
{
|
||
|
if (nameCache.containsKey(uuid))
|
||
|
return (String)nameCache.get(uuid);
|
||
|
try
|
||
|
{
|
||
|
HttpURLConnection connection = (HttpURLConnection)new URL(
|
||
|
String.format("https://api.mojang.com/user/profiles/%s/names", new Object[] { UUIDTypeAdapter.fromUUID(uuid) }))
|
||
|
.openConnection();
|
||
|
connection.setReadTimeout(5000);
|
||
|
UUIDFetcher[] nameHistory = (UUIDFetcher[])gson.fromJson(
|
||
|
new BufferedReader(new InputStreamReader(connection.getInputStream())),
|
||
|
[Lde.joethei.core.api.NPC.UUIDFetcher.class);
|
||
|
UUIDFetcher currentNameData = nameHistory[(nameHistory.length - 1)];
|
||
|
uuidCache.put(currentNameData.name.toLowerCase(), uuid);
|
||
|
nameCache.put(uuid, currentNameData.name);
|
||
|
return currentNameData.name;
|
||
|
} catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public static abstract class Acceptor<T>
|
||
|
implements Runnable
|
||
|
{
|
||
|
private NPC.UUIDFetcher.Consumer<T> consumer;
|
||
|
|
||
|
public Acceptor(NPC.UUIDFetcher.Consumer<T> consumer)
|
||
|
{
|
||
|
this.consumer = consumer;
|
||
|
}
|
||
|
|
||
|
public abstract T getValue();
|
||
|
|
||
|
public void run() {
|
||
|
this.consumer.accept(getValue());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static abstract interface Consumer<T>
|
||
|
{
|
||
|
public abstract void accept(T paramT);
|
||
|
}
|
||
|
}
|
||
|
}
|