PlotSquared/src/main/java/com/plotsquared/bukkit/titles/DefaultTitleManager.java

441 lines
12 KiB
Java
Raw Normal View History

2015-07-26 16:51:12 +02:00
package com.plotsquared.bukkit.titles;
2015-01-18 12:11:51 -08:00
import java.lang.reflect.Field;
2015-02-03 12:47:10 +11:00
import java.lang.reflect.InvocationTargetException;
2015-01-18 12:11:51 -08:00
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
2015-07-31 00:25:16 +10:00
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
2015-01-18 12:11:51 -08:00
/**
* [ PlotSquared DefaultTitleManager by Maxim Van de Wynckel ]
*
* @version 1.1.0
* @author Maxim Van de Wynckel
2015-02-20 17:34:19 +11:00
*
2015-01-18 12:11:51 -08:00
*/
2015-09-11 20:09:22 +10:00
public class DefaultTitleManager
{
2015-02-20 17:34:19 +11:00
/* Title packet */
private Class<?> packetTitle;
/* Title packet actions ENUM */
private Class<?> packetActions;
/* Chat serializer */
private Class<?> nmsChatSerializer;
private Class<?> chatBaseComponent;
/* Title text and color */
private String title = "";
private ChatColor titleColor = ChatColor.WHITE;
/* Subtitle text and color */
private String subtitle = "";
private ChatColor subtitleColor = ChatColor.WHITE;
/* Title timings */
private int fadeInTime = -1;
private int stayTime = -1;
private int fadeOutTime = -1;
private boolean ticks = false;
private static final Map<Class<?>, Class<?>> CORRESPONDING_TYPES = new HashMap<Class<?>, Class<?>>();
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Create a new 1.8 title
*
* @param title
* Title
2015-02-23 12:32:27 +11:00
* @throws ClassNotFoundException
2015-02-20 17:34:19 +11:00
*/
2015-09-11 20:09:22 +10:00
public DefaultTitleManager(final String title) throws ClassNotFoundException
{
2015-02-20 17:34:19 +11:00
this.title = title;
loadClasses();
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Create a new 1.8 title
*
* @param title
* Title text
* @param subtitle
* Subtitle text
2015-02-23 12:32:27 +11:00
* @throws ClassNotFoundException
2015-02-20 17:34:19 +11:00
*/
2015-09-11 20:09:22 +10:00
public DefaultTitleManager(final String title, final String subtitle) throws ClassNotFoundException
{
2015-02-20 17:34:19 +11:00
this.title = title;
this.subtitle = subtitle;
loadClasses();
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Copy 1.8 title
*
* @param title
* Title
2015-02-23 12:32:27 +11:00
* @throws ClassNotFoundException
2015-02-20 17:34:19 +11:00
*/
2015-09-11 20:09:22 +10:00
public DefaultTitleManager(final DefaultTitleManager title) throws ClassNotFoundException
{
2015-02-20 17:34:19 +11:00
// Copy title
this.title = title.title;
2015-09-11 20:09:22 +10:00
subtitle = title.subtitle;
titleColor = title.titleColor;
subtitleColor = title.subtitleColor;
fadeInTime = title.fadeInTime;
fadeOutTime = title.fadeOutTime;
stayTime = title.stayTime;
ticks = title.ticks;
2015-02-20 17:34:19 +11:00
loadClasses();
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Create a new 1.8 title
*
* @param title
* Title text
* @param subtitle
* Subtitle text
* @param fadeInTime
* Fade in time
* @param stayTime
* Stay on screen time
* @param fadeOutTime
* Fade out time
2015-02-23 12:32:27 +11:00
* @throws ClassNotFoundException
2015-02-20 17:34:19 +11:00
*/
2015-09-11 20:09:22 +10:00
public DefaultTitleManager(final String title, final String subtitle, final int fadeInTime, final int stayTime, final int fadeOutTime) throws ClassNotFoundException
{
2015-02-20 17:34:19 +11:00
this.title = title;
this.subtitle = subtitle;
this.fadeInTime = fadeInTime;
this.stayTime = stayTime;
this.fadeOutTime = fadeOutTime;
loadClasses();
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Load spigot and NMS classes
2015-02-23 12:32:27 +11:00
* @throws ClassNotFoundException
2015-02-20 17:34:19 +11:00
*/
2015-09-11 20:09:22 +10:00
private void loadClasses() throws ClassNotFoundException
{
packetTitle = getNMSClass("PacketPlayOutTitle");
packetActions = getNMSClass("EnumTitleAction");
chatBaseComponent = getNMSClass("IChatBaseComponent");
nmsChatSerializer = getNMSClass("ChatSerializer");
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Set title text
*
* @param title
* Title
*/
2015-09-11 20:09:22 +10:00
public void setTitle(final String title)
{
2015-02-20 17:34:19 +11:00
this.title = title;
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Get title text
*
* @return Title text
*/
2015-09-11 20:09:22 +10:00
public String getTitle()
{
return title;
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Set subtitle text
*
* @param subtitle
* Subtitle text
*/
2015-09-11 20:09:22 +10:00
public void setSubtitle(final String subtitle)
{
2015-02-20 17:34:19 +11:00
this.subtitle = subtitle;
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Get subtitle text
*
* @return Subtitle text
*/
2015-09-11 20:09:22 +10:00
public String getSubtitle()
{
return subtitle;
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Set the title color
*
* @param color
* Chat color
*/
2015-09-11 20:09:22 +10:00
public void setTitleColor(final ChatColor color)
{
titleColor = color;
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Set the subtitle color
*
* @param color
* Chat color
*/
2015-09-11 20:09:22 +10:00
public void setSubtitleColor(final ChatColor color)
{
subtitleColor = color;
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Set title fade in time
*
* @param time
* Time
*/
2015-09-11 20:09:22 +10:00
public void setFadeInTime(final int time)
{
fadeInTime = time;
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Set title fade out time
*
* @param time
* Time
*/
2015-09-11 20:09:22 +10:00
public void setFadeOutTime(final int time)
{
fadeOutTime = time;
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Set title stay time
*
* @param time
* Time
*/
2015-09-11 20:09:22 +10:00
public void setStayTime(final int time)
{
stayTime = time;
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Set timings to ticks
*/
2015-09-11 20:09:22 +10:00
public void setTimingsToTicks()
{
ticks = true;
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Set timings to seconds
*/
2015-09-11 20:09:22 +10:00
public void setTimingsToSeconds()
{
ticks = false;
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Send the title to a player
*
* @param player
* Player
2015-02-23 12:32:27 +11:00
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
2015-02-20 17:34:19 +11:00
*/
2015-09-11 20:09:22 +10:00
public void send(final Player player) throws Exception
{
if (packetTitle != null)
{
2015-02-20 17:34:19 +11:00
// First reset previous settings
resetTitle(player);
// Send timings first
final Object handle = getHandle(player);
final Object connection = getField(handle.getClass(), "playerConnection").get(handle);
2015-09-11 20:09:22 +10:00
final Object[] actions = packetActions.getEnumConstants();
2015-02-20 17:34:19 +11:00
final Method sendPacket = getMethod(connection.getClass(), "sendPacket");
2015-09-11 20:09:22 +10:00
Object packet = packetTitle.getConstructor(packetActions, chatBaseComponent, Integer.TYPE, Integer.TYPE, Integer.TYPE).newInstance(actions[2], null,
fadeInTime * (ticks ? 1 : 20), stayTime * (ticks ? 1 : 20), fadeOutTime * (ticks ? 1 : 20));
2015-02-20 17:34:19 +11:00
// Send if set
2015-09-11 20:09:22 +10:00
if ((fadeInTime != -1) && (fadeOutTime != -1) && (stayTime != -1))
{
2015-02-20 17:34:19 +11:00
sendPacket.invoke(connection, packet);
}
// Send title
2015-09-11 20:09:22 +10:00
Object serialized = getMethod(nmsChatSerializer, "a", String.class).invoke(null,
"{text:\"" + ChatColor.translateAlternateColorCodes('&', title) + "\",color:" + titleColor.name().toLowerCase() + "}");
packet = packetTitle.getConstructor(packetActions, chatBaseComponent).newInstance(actions[0], serialized);
2015-02-20 17:34:19 +11:00
sendPacket.invoke(connection, packet);
2015-09-11 20:09:22 +10:00
if (subtitle != "")
{
2015-02-20 17:34:19 +11:00
// Send subtitle if present
2015-09-11 20:09:22 +10:00
serialized = getMethod(nmsChatSerializer, "a", String.class).invoke(null,
"{text:\"" + ChatColor.translateAlternateColorCodes('&', subtitle) + "\",color:" + subtitleColor.name().toLowerCase() + "}");
packet = packetTitle.getConstructor(packetActions, chatBaseComponent).newInstance(actions[1], serialized);
2015-02-20 17:34:19 +11:00
sendPacket.invoke(connection, packet);
}
}
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Broadcast the title to all players
2015-02-23 12:32:27 +11:00
* @throws Exception
2015-02-20 17:34:19 +11:00
*/
2015-09-11 20:09:22 +10:00
public void broadcast() throws Exception
{
for (final Player p : Bukkit.getOnlinePlayers())
{
2015-02-20 17:34:19 +11:00
send(p);
}
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Clear the title
*
* @param player
* Player
2015-09-11 20:09:22 +10:00
* @throws IllegalAccessException
* @throws IllegalArgumentException
2015-02-20 17:34:19 +11:00
*/
2015-09-11 20:09:22 +10:00
public void clearTitle(final Player player) throws Exception
{
// Send timings first
final Object handle = getHandle(player);
final Object connection = getField(handle.getClass(), "playerConnection").get(handle);
final Object[] actions = packetActions.getEnumConstants();
final Method sendPacket = getMethod(connection.getClass(), "sendPacket");
final Object packet = packetTitle.getConstructor(packetActions, chatBaseComponent).newInstance(actions[3], null);
sendPacket.invoke(connection, packet);
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-02-20 17:34:19 +11:00
/**
* Reset the title settings
*
* @param player
* Player
*/
2015-09-11 20:09:22 +10:00
public void resetTitle(final Player player) throws Exception
{
// Send timings first
2015-03-15 13:08:45 +11:00
final Object handle = getHandle(player);
final Object connection = getField(handle.getClass(), "playerConnection").get(handle);
2015-09-11 20:09:22 +10:00
final Object[] actions = packetActions.getEnumConstants();
2015-03-15 13:08:45 +11:00
final Method sendPacket = getMethod(connection.getClass(), "sendPacket");
2015-09-11 20:09:22 +10:00
final Object packet = packetTitle.getConstructor(packetActions, chatBaseComponent).newInstance(actions[4], null);
2015-03-15 13:08:45 +11:00
sendPacket.invoke(connection, packet);
2015-02-20 17:34:19 +11:00
}
2015-02-23 12:32:27 +11:00
2015-09-11 20:09:22 +10:00
private Class<?> getPrimitiveType(final Class<?> clazz)
{
2015-02-20 17:34:19 +11:00
return CORRESPONDING_TYPES.containsKey(clazz) ? CORRESPONDING_TYPES.get(clazz) : clazz;
}
2015-02-23 12:32:27 +11:00
2015-09-11 20:09:22 +10:00
private Class<?>[] toPrimitiveTypeArray(final Class<?>[] classes)
{
2015-02-20 17:34:19 +11:00
final int a = classes != null ? classes.length : 0;
final Class<?>[] types = new Class<?>[a];
2015-09-11 20:09:22 +10:00
for (int i = 0; i < a; i++)
{
2015-02-20 17:34:19 +11:00
types[i] = getPrimitiveType(classes[i]);
}
return types;
}
2015-02-23 12:32:27 +11:00
2015-09-11 20:09:22 +10:00
private static boolean equalsTypeArray(final Class<?>[] a, final Class<?>[] o)
{
if (a.length != o.length) { return false; }
for (int i = 0; i < a.length; i++)
{
if (!a[i].equals(o[i]) && !a[i].isAssignableFrom(o[i])) { return false; }
2015-02-20 17:34:19 +11:00
}
return true;
}
2015-02-23 12:32:27 +11:00
2015-09-11 20:09:22 +10:00
private Object getHandle(final Object obj)
{
try
{
2015-02-20 17:34:19 +11:00
return getMethod("getHandle", obj.getClass()).invoke(obj);
2015-09-11 20:09:22 +10:00
}
catch (final Exception e)
{
2015-02-20 17:34:19 +11:00
e.printStackTrace();
return null;
}
}
2015-02-23 12:32:27 +11:00
2015-09-11 20:09:22 +10:00
private Method getMethod(final String name, final Class<?> clazz, final Class<?>... paramTypes)
{
2015-02-20 17:34:19 +11:00
final Class<?>[] t = toPrimitiveTypeArray(paramTypes);
2015-09-11 20:09:22 +10:00
for (final Method m : clazz.getMethods())
{
2015-02-20 17:34:19 +11:00
final Class<?>[] types = toPrimitiveTypeArray(m.getParameterTypes());
2015-09-11 20:09:22 +10:00
if (m.getName().equals(name) && equalsTypeArray(types, t)) { return m; }
2015-02-20 17:34:19 +11:00
}
return null;
}
2015-02-23 12:32:27 +11:00
2015-09-11 20:09:22 +10:00
private String getVersion()
{
2015-02-20 17:34:19 +11:00
final String name = Bukkit.getServer().getClass().getPackage().getName();
final String version = name.substring(name.lastIndexOf('.') + 1) + ".";
return version;
}
2015-02-23 12:32:27 +11:00
2015-09-11 20:09:22 +10:00
private Class<?> getNMSClass(final String className) throws ClassNotFoundException
{
2015-02-20 17:34:19 +11:00
final String fullName = "net.minecraft.server." + getVersion() + className;
Class<?> clazz = null;
clazz = Class.forName(fullName);
return clazz;
}
2015-02-23 12:32:27 +11:00
2015-09-11 20:09:22 +10:00
private Field getField(final Class<?> clazz, final String name)
{
try
{
2015-02-20 17:34:19 +11:00
final Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field;
2015-09-11 20:09:22 +10:00
}
catch (final Exception e)
{
2015-02-20 17:34:19 +11:00
e.printStackTrace();
return null;
}
}
2015-02-23 12:32:27 +11:00
2015-09-11 20:09:22 +10:00
private Method getMethod(final Class<?> clazz, final String name, final Class<?>... args)
{
for (final Method m : clazz.getMethods())
{
if (m.getName().equals(name) && ((args.length == 0) || ClassListEqual(args, m.getParameterTypes())))
{
2015-02-20 17:34:19 +11:00
m.setAccessible(true);
return m;
}
}
return null;
}
2015-02-23 12:32:27 +11:00
2015-09-11 20:09:22 +10:00
private boolean ClassListEqual(final Class<?>[] l1, final Class<?>[] l2)
{
2015-02-20 17:34:19 +11:00
boolean equal = true;
2015-09-11 20:09:22 +10:00
if (l1.length != l2.length) { return false; }
for (int i = 0; i < l1.length; i++)
{
if (l1[i] != l2[i])
{
2015-02-20 17:34:19 +11:00
equal = false;
break;
}
}
return equal;
}
2015-01-18 12:11:51 -08:00
}