diff --git a/src/com/massivecraft/massivecore/AspectColl.java b/src/com/massivecraft/massivecore/AspectColl.java index 31c8086f..82adcfbc 100644 --- a/src/com/massivecraft/massivecore/AspectColl.java +++ b/src/com/massivecraft/massivecore/AspectColl.java @@ -38,7 +38,7 @@ public class AspectColl extends Coll List ret = new ArrayList(); for (Aspect aspect : this.getAll()) { - if(aspect.isRegistered() == false) continue; + if (aspect.isRegistered() == false) continue; ret.add(aspect); } return ret; @@ -49,8 +49,8 @@ public class AspectColl extends Coll List ret = new ArrayList(); for (Aspect aspect : this.getAll()) { - if(aspect.isRegistered() == false) continue; - if((aspect.getMultiverse() != multiverse) == normal) continue; + if (aspect.isRegistered() == false) continue; + if ((aspect.getMultiverse() != multiverse) == normal) continue; ret.add(aspect); } return ret; diff --git a/src/com/massivecraft/massivecore/MassiveCore.java b/src/com/massivecraft/massivecore/MassiveCore.java index f7a165f3..cb9d03d7 100644 --- a/src/com/massivecraft/massivecore/MassiveCore.java +++ b/src/com/massivecraft/massivecore/MassiveCore.java @@ -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; diff --git a/src/com/massivecraft/massivecore/Multiverse.java b/src/com/massivecraft/massivecore/Multiverse.java index df1f2765..b0a9c268 100644 --- a/src/com/massivecraft/massivecore/Multiverse.java +++ b/src/com/massivecraft/massivecore/Multiverse.java @@ -161,7 +161,7 @@ public class Multiverse extends Entity { for (Set worldNames : this.uw.values()) { - if(worldNames.remove(worldName)) return true; + if (worldNames.remove(worldName)) return true; } return false; } diff --git a/src/com/massivecraft/massivecore/mixin/Mixin.java b/src/com/massivecraft/massivecore/mixin/Mixin.java index 17fbbee3..703f81d8 100644 --- a/src/com/massivecraft/massivecore/mixin/Mixin.java +++ b/src/com/massivecraft/massivecore/mixin/Mixin.java @@ -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 // -------------------------------------------- // diff --git a/src/com/massivecraft/massivecore/mixin/TitleMixin.java b/src/com/massivecraft/massivecore/mixin/TitleMixin.java new file mode 100644 index 00000000..9ed147c0 --- /dev/null +++ b/src/com/massivecraft/massivecore/mixin/TitleMixin.java @@ -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(); +} diff --git a/src/com/massivecraft/massivecore/mixin/TitleMixinAbstract.java b/src/com/massivecraft/massivecore/mixin/TitleMixinAbstract.java new file mode 100644 index 00000000..38cad175 --- /dev/null +++ b/src/com/massivecraft/massivecore/mixin/TitleMixinAbstract.java @@ -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); + } + +} diff --git a/src/com/massivecraft/massivecore/mixin/TitleMixinDefault.java b/src/com/massivecraft/massivecore/mixin/TitleMixinDefault.java new file mode 100644 index 00000000..f1f7588a --- /dev/null +++ b/src/com/massivecraft/massivecore/mixin/TitleMixinDefault.java @@ -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(); + } + +} diff --git a/src/com/massivecraft/massivecore/teleport/EngineScheduledTeleport.java b/src/com/massivecraft/massivecore/teleport/EngineScheduledTeleport.java index 9e6122d8..678fa2f7 100644 --- a/src/com/massivecraft/massivecore/teleport/EngineScheduledTeleport.java +++ b/src/com/massivecraft/massivecore/teleport/EngineScheduledTeleport.java @@ -122,7 +122,7 @@ public class EngineScheduledTeleport extends EngineAbstract Entity entity = event.getEntity(); // ... and that entity is a player ... - if(!(entity instanceof Player)) return; + if (!(entity instanceof Player)) return; Player player = (Player)entity; // ... cancel teleport! diff --git a/src/com/massivecraft/massivecore/util/TitleUtil.java b/src/com/massivecraft/massivecore/util/TitleUtil.java new file mode 100644 index 00000000..f82b10ee --- /dev/null +++ b/src/com/massivecraft/massivecore/util/TitleUtil.java @@ -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; + } + +}