TitleUtil without NMS

And a TitleMixin
This commit is contained in:
Magnus Ulf 2015-01-21 22:18:29 +01:00 committed by Olof Larsson
parent e93f7c12d8
commit 59edd6917f
9 changed files with 291 additions and 6 deletions

View File

@ -18,10 +18,10 @@ import com.massivecraft.massivecore.adapter.JsonElementAdapter;
import com.massivecraft.massivecore.adapter.MassiveListAdapter;
import com.massivecraft.massivecore.adapter.MassiveMapAdapter;
import com.massivecraft.massivecore.adapter.MassiveSetAdapter;
import com.massivecraft.massivecore.adapter.MassiveTreeMapAdapter;
import com.massivecraft.massivecore.adapter.MassiveTreeSetAdapter;
import com.massivecraft.massivecore.adapter.ModdedEnumTypeAdapter;
import com.massivecraft.massivecore.adapter.PlayerInventoryAdapter;
import com.massivecraft.massivecore.adapter.MassiveTreeMapAdapter;
import com.massivecraft.massivecore.adapter.UUIDAdapter;
import com.massivecraft.massivecore.cmd.massivecore.CmdMassiveCore;
import com.massivecraft.massivecore.cmd.massivecore.CmdMassiveCoreBuffer;

View File

@ -56,6 +56,10 @@ public class Mixin
public static MessageMixin getMessageMixin() { return messageMixin; }
public static void setMessageMixin(MessageMixin val) { messageMixin = val; }
private static TitleMixin titleMixin = TitleMixinDefault.get();
public static TitleMixin getTitleMixin() { return titleMixin; }
public static void setTitleMixin(TitleMixin val) { titleMixin = val; }
private static KickMixin kickMixin = KickMixinDefault.get();
public static KickMixin getKickMixin() { return kickMixin; }
public static void setKickMixin(KickMixin val) { kickMixin = val; }
@ -386,6 +390,28 @@ public class Mixin
return getMessageMixin().msgOne(senderObject, msgs);
}
// -------------------------------------------- //
// STATIC EXPOSE: TITLE
// -------------------------------------------- //
// Default
public static boolean sendTitleMessage(Object watcherObject, int fadeIn, int stay, int fadeOut, String mainTitle, String subTitle)
{
return getTitleMixin().sendTitleMessage(watcherObject, fadeIn, stay, fadeOut, mainTitle, subTitle);
}
// Parsed
public static boolean sendTitleMsg(Object watcherObject, int fadeIn, int stay, int fadeOut, String mainTitle, String subTitle)
{
return getTitleMixin().sendTitleMsg(watcherObject, fadeIn, stay, fadeOut, mainTitle, subTitle);
}
// Available
public static boolean isTitlesAvailable()
{
return getTitleMixin().isTitlesAvailable();
}
// -------------------------------------------- //
// STATIC EXPOSE: KICK
// -------------------------------------------- //

View File

@ -0,0 +1,13 @@
package com.massivecraft.massivecore.mixin;
public interface TitleMixin
{
// Abstract
public boolean sendTitleMessage(Object watcherObject, int fadeIn, int stay, int fadeOut, String mainTitle, String subTitle);
// Parsed
public boolean sendTitleMsg(Object watcherObject, int fadeIn, int stay, int fadeOut, String mainTitle, String subTitle);
// Available
public boolean isTitlesAvailable();
}

View File

@ -0,0 +1,16 @@
package com.massivecraft.massivecore.mixin;
import com.massivecraft.massivecore.util.Txt;
public abstract class TitleMixinAbstract implements TitleMixin
{
// Parsed
@Override
public boolean sendTitleMsg(Object watcherObject, int fadeIn, int stay, int fadeOut, String mainTitle, String subTitle)
{
if (mainTitle != null) mainTitle = Txt.parse(mainTitle);
if (subTitle != null) subTitle = Txt.parse(subTitle);
return this.sendTitleMessage(watcherObject, fadeIn, stay, fadeOut, mainTitle, subTitle);
}
}

View File

@ -0,0 +1,41 @@
package com.massivecraft.massivecore.mixin;
import org.bukkit.entity.Player;
import com.massivecraft.massivecore.util.IdUtil;
import com.massivecraft.massivecore.util.TitleUtil;
public class TitleMixinDefault extends TitleMixinAbstract
{
// -------------------------------------------- //
// INSTANCE & CONSTRUCT
// -------------------------------------------- //
private static TitleMixinDefault i = new TitleMixinDefault();
public static TitleMixinDefault get() { return i; }
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public boolean sendTitleMessage(Object watcherObject, int fadeIn, int stay, int fadeOut, String mainTitle, String subTitle)
{
// Get the player
Player player = IdUtil.getPlayer(watcherObject);
if (player == null) return false;
// If we don't send any message (empty is ok) we might end up displaying old messages.
if (subTitle == null) subTitle = "";
if (mainTitle == null) mainTitle = "";
return TitleUtil.sendTitle(player, fadeIn, stay, fadeOut, mainTitle, subTitle);
}
@Override
public boolean isTitlesAvailable()
{
return TitleUtil.isAvailable();
}
}

View File

@ -0,0 +1,189 @@
package com.massivecraft.massivecore.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.logging.Level;
import org.bukkit.entity.Player;
import org.json.simple.JSONObject;
import com.massivecraft.massivecore.MassiveCore;
import com.massivecraft.massivecore.particleeffect.ReflectionUtils;
import com.massivecraft.massivecore.particleeffect.ReflectionUtils.PackageType;
public final class TitleUtil
{
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
private static boolean useTitles = false;
// The enums used to tell which packet it is.
// They correspond to the commands with the same name.
private static Class<?> titleEnumClass;
private static Enum<?> titleEnum;
private static Enum<?> subtitleEnum;
private static Enum<?> timesEnum;
// Method used to prepare text so it can be send
private static Method chatSerializer;
// The object we send instead of a string
private static Class<?> iChatBaseComponent;
// Handling the players conenction
private static Method getHandle;
private static Field playerConnection;
private static Method sendPacket;
// The packet and its constructor
private static Constructor<?> packetConstructor;
private static Constructor<?> packetConstructorTimes;
// -------------------------------------------- //
// SETUP
// -------------------------------------------- //
static
{
try
{
// The enum used
titleEnumClass = PackageType.MINECRAFT_SERVER.getClass("EnumTitleAction");
// Get the enum values.
for (Object o : titleEnumClass.getEnumConstants())
{
Enum<?> e = (Enum<?>) o;
if (e.name().equalsIgnoreCase("TITLE")) titleEnum = e;
else if (e.name().equalsIgnoreCase("SUBTITLE")) subtitleEnum = e;
else if (e.name().equalsIgnoreCase("TIMES")) timesEnum = e;
}
// Get chatserializer and chat component.
iChatBaseComponent = PackageType.MINECRAFT_SERVER.getClass("IChatBaseComponent");
chatSerializer = PackageType.MINECRAFT_SERVER.getClass("ChatSerializer").getDeclaredMethod("a", String.class);
// Get packet and it's constructor
Class<?> packetClass = PackageType.MINECRAFT_SERVER.getClass("PacketPlayOutTitle");
packetConstructor = ReflectionUtils.getConstructor(packetClass, titleEnumClass, iChatBaseComponent);
packetConstructorTimes = ReflectionUtils.getConstructor(packetClass, titleEnumClass, iChatBaseComponent, Integer.class, Integer.class, Integer.class);
// Player connection
getHandle = ReflectionUtils.getMethod("CraftPlayer", PackageType.CRAFTBUKKIT_ENTITY, "getHandle");
playerConnection = ReflectionUtils.getField("EntityPlayer", PackageType.MINECRAFT_SERVER, false, "playerConnection");
sendPacket = ReflectionUtils.getMethod(playerConnection.getType(), "sendPacket", PackageType.MINECRAFT_SERVER.getClass("Packet"));
// Set accesible
chatSerializer.setAccessible(true);
packetConstructor.setAccessible(true);
packetConstructorTimes.setAccessible(true);
getHandle.setAccessible(true);
playerConnection.setAccessible(true);
sendPacket.setAccessible(true);
// This suceeded, we use titles.
useTitles = true;
}
catch (Exception e)
{
MassiveCore.get().log(Level.INFO, "If you use 1.7.X or below, disregard this error");
MassiveCore.get().log(Level.INFO, "If you use 1.8.X or above, please report at https://github.com/MassiveCraft/MassiveCore/issues");
e.printStackTrace();
MassiveCore.get().log(Level.INFO, "If you use 1.7.X or below, disregard this error");
MassiveCore.get().log(Level.INFO, "If you use 1.8.X or above, please report at https://github.com/MassiveCraft/MassiveCore/issues");
// It didn't suceed, we will not use titles.
useTitles = false;
}
}
// -------------------------------------------- //
// AVAILABLE
// -------------------------------------------- //
public static boolean isAvailable()
{
return useTitles;
}
// -------------------------------------------- //
// SEND TITLES
// -------------------------------------------- //
public static boolean sendTitle(Player player, int fadeIn, int stay, int fadeOut, String title, String subtitle)
{
if ( ! useTitles)
{
return false;
}
try
{
// Fadein, stay, fadeout
Object timesPacket = packetConstructorTimes.newInstance(timesEnum, null, fadeIn, stay, fadeOut);
sendPacket.invoke(playerConnection.get( getHandle.invoke(player) ), timesPacket);
}
catch (Exception e)
{
e.printStackTrace();
// So we failed, didn't work.
return false;
}
if (title != null)
{
title = toJson(title);
try
{
// Title
Object titleMain = chatSerializer.invoke(null, title);
Object titlePacket = packetConstructor.newInstance(titleEnum, titleMain);
sendPacket.invoke(playerConnection.get(getHandle.invoke(player)), titlePacket);
}
catch (Exception e)
{
e.printStackTrace();
// So we failed, didn't work.
return false;
}
}
if (subtitle != null)
{
subtitle = toJson(subtitle);
try
{
// SubTitle
Object subtitleMain = chatSerializer.invoke(null, subtitle);
Object subtitlesPacket = packetConstructor.newInstance(subtitleEnum, subtitleMain);
sendPacket.invoke(playerConnection.get(getHandle.invoke(player)), subtitlesPacket);
}
catch (Exception e)
{
e.printStackTrace();
// So we failed, didn't work.
return false;
}
}
//It worked.
return true;
}
// -------------------------------------------- //
// JSON
// -------------------------------------------- //
public static String toJson(String str)
{
str = JSONObject.escape(str);
str = "{\"text\": \"" + str + "\"}";
return str;
}
}