Util Send hotbar messages

Discussion in 'Resources' started by Zombie_Striker, Jan 2, 2017.

Thread Status:
Not open for further replies.
  1. Offline

    Zombie_Striker

    Hello, I have been working on a plugin that is meant to send messages to player's hotbars. Since there is no API methods for doing this yet, nor does there seem to be any threads/utils like this, I have decided to post the class here.

    Code:java
    1. import java.lang.reflect.*;
    2. import java.util.logging.Level;
    3.  
    4. import org.bukkit.Bukkit;
    5. import org.bukkit.entity.Player;
    6.  
    7. public class HotbarMessager {
    8.  
    9. // These are the Class instances. Needed to get fields or methods for classes.
    10. private static Class<?> CRAFTPLAYERCLASS, PACKET_PLAYER_CHAT_CLASS, ICHATCOMP, CHATMESSAGE, PACKET_CLASS,
    11. CHAT_MESSAGE_TYPE_CLASS;
    12.  
    13. private static Field PLAYERCONNECTION;
    14. private static Method GETHANDLE, SENDPACKET;
    15.  
    16. // These are the constructors for those classes. Need to create new objects.
    17. private static Constructor<?> PACKET_PLAYER_CHAT_CONSTRUCTOR, CHATMESSAGE_CONSTRUCTOR;
    18.  
    19. // Used in 1.12+. Bytes are replaced with this enum
    20. private static Object CHAT_MESSAGE_TYPE_ENUM_OBJECT;
    21.  
    22. // This is the server version. This is how we know the server version.
    23. private static final String SERVER_VERSION;
    24. private static boolean useByte = false;
    25. static {
    26. // This gets the server version.
    27. String name = Bukkit.getServer().getClass().getName();
    28. name = name.substring(name.indexOf("craftbukkit.") + "craftbukkit.".length());
    29. name = name.substring(0, name.indexOf("."));
    30. SERVER_VERSION = name;
    31. try {
    32. // This here sets the class fields.
    33. CRAFTPLAYERCLASS = Class.forName("org.bukkit.craftbukkit." + SERVER_VERSION + ".entity.CraftPlayer");
    34. PACKET_PLAYER_CHAT_CLASS = Class.forName("net.minecraft.server." + SERVER_VERSION + ".PacketPlayOutChat");
    35. PACKET_CLASS = Class.forName("net.minecraft.server." + SERVER_VERSION + ".Packet");
    36. ICHATCOMP = Class.forName("net.minecraft.server." + SERVER_VERSION + ".IChatBaseComponent");
    37. GETHANDLE = CRAFTPLAYERCLASS.getMethod("getHandle");
    38. PLAYERCONNECTION = GETHANDLE.getReturnType().getField("playerConnection");
    39. SENDPACKET = PLAYERCONNECTION.getType().getMethod("sendPacket", PACKET_CLASS);
    40. try {
    41. CHAT_MESSAGE_TYPE_CLASS = Class.forName("net.minecraft.server." + SERVER_VERSION + ".ChatMessageType");
    42. CHAT_MESSAGE_TYPE_ENUM_OBJECT = CHAT_MESSAGE_TYPE_CLASS.getEnumConstants()[2];
    43.  
    44. PACKET_PLAYER_CHAT_CONSTRUCTOR = PACKET_PLAYER_CHAT_CLASS.getConstructor(ICHATCOMP,
    45. CHAT_MESSAGE_TYPE_CLASS);
    46. } catch (NoSuchMethodException e) {
    47. PACKET_PLAYER_CHAT_CONSTRUCTOR = PACKET_PLAYER_CHAT_CLASS.getConstructor(ICHATCOMP, byte.class);
    48. useByte = true;
    49. }
    50. CHATMESSAGE = Class.forName("net.minecraft.server." + SERVER_VERSION + ".ChatMessage");
    51. CHATMESSAGE_CONSTRUCTOR = CHATMESSAGE.getConstructor(String.class, Object[].class);
    52. } catch (Exception e) {
    53. e.printStackTrace();
    54. }
    55. }
    56.  
    57. /**
    58.   * Sends the hotbar message 'message' to the player 'player'
    59.   *
    60.   * @param player
    61.   * @param message
    62.   * @throws Exception
    63.   */
    64. public static void sendHotBarMessage(Player player, String message) throws Exception {
    65. try {
    66. // This creates the IChatComponentBase instance
    67. Object icb = CHATMESSAGE_CONSTRUCTOR.newInstance(message, new Object[0]);
    68. // This creates the packet
    69. Object packet;
    70. if (useByte)
    71. packet = PACKET_PLAYER_CHAT_CONSTRUCTOR.newInstance(icb, (byte) 2);
    72. else
    73. packet = PACKET_PLAYER_CHAT_CONSTRUCTOR.newInstance(icb, CHAT_MESSAGE_TYPE_ENUM_OBJECT);
    74. // This casts the player to a craftplayer
    75. Object craftplayerInst = CRAFTPLAYERCLASS.cast(player);
    76. // This invokes the method above.
    77. Object methodhHandle = GETHANDLE.invoke(craftplayerInst);
    78. // This gets the player's connection
    79. Object playerConnection = PLAYERCONNECTION.get(methodhHandle);
    80. // This sends the packet.
    81. SENDPACKET.invoke(playerConnection, packet);
    82. } catch (Exception e) {
    83. failsafe("sendHotBarMessage");
    84. throw e;
    85. }
    86. }
    87.  
    88. private static void failsafe(String message) {
    89. Bukkit.getLogger().log(Level.WARNING,
    90. "[PluginConstructorAPI] HotBarMessager disabled! Something went wrong with: " + message);
    91. Bukkit.getLogger().log(Level.WARNING, "[PluginConstructorAPI] Report this to Zombie_Striker");
    92. Bukkit.getLogger().log(Level.WARNING, "[PluginConstructorAPI] Needed Information: " + Bukkit.getName() + ", "
    93. + Bukkit.getVersion() + ", " + Bukkit.getBukkitVersion());
    94. Bukkit.getLogger().log(Level.WARNING,
    95. "[PluginConstructorAPI] [URL]https://github.com/ZombieStriker/PluginConstructorAPI[/URL]");
    96. }
    97. }
    98.  
    99.  

    OLD (open)

    Code:java
    1.  
    2.  
    3.  
    4. import java.lang.reflect.*;
    5.  
    6. import org.bukkit.Bukkit;
    7. import org.bukkit.entity.Player;
    8.  
    9. public class HotbarMessager {
    10.  
    11. /**
    12.   * These are the Class instances. Use these to get fields or methods for
    13.   * classes.
    14.   */
    15. private static Class<?> CRAFTPLAYERCLASS, PACKET_PLAYER_CHAT_CLASS, ICHATCOMP, CHATMESSAGE, PACKET_CLASS,
    16. CHAT_MESSAGE_TYPE_CLASS;
    17.  
    18. private static Field PLAYERCONNECTION;
    19. private static Method GETHANDLE, SENDPACKET;
    20.  
    21. /**
    22.   * These are the constructors for those classes. You need these to create new
    23.   * objects.
    24.   */
    25. private static Constructor<?> PACKET_PLAYER_CHAT_CONSTRUCTOR, CHATMESSAGE_CONSTRUCTOR;
    26. /**
    27.   * Used in 1.12+. Bytes are replaced with this enum
    28.   */
    29. private static Object CHAT_MESSAGE_TYPE_ENUM_OBJECT;
    30.  
    31. /**
    32.   * This is the server version. This is how we know the server version.
    33.   */
    34. private static final String SERVER_VERSION;
    35. static {
    36. // This gets the server version.
    37. String name = Bukkit.getServer().getClass().getName();
    38. name = name.substring(name.indexOf("craftbukkit.") + "craftbukkit.".length());
    39. name = name.substring(0, name.indexOf("."));
    40. SERVER_VERSION = name;
    41.  
    42. try {
    43. // This here sets the class fields.
    44. CRAFTPLAYERCLASS = Class.forName("org.bukkit.craftbukkit." + SERVER_VERSION + ".entity.CraftPlayer");
    45. PACKET_PLAYER_CHAT_CLASS = Class.forName("net.minecraft.server." + SERVER_VERSION + ".PacketPlayOutChat");
    46. PACKET_CLASS = Class.forName("net.minecraft.server." + SERVER_VERSION + ".Packet");
    47. ICHATCOMP = Class.forName("net.minecraft.server." + SERVER_VERSION + ".IChatBaseComponent");
    48. GETHANDLE = CRAFTPLAYERCLASS.getMethod("getHandle");
    49. PLAYERCONNECTION = GETHANDLE.getReturnType().getField("playerConnection");
    50. SENDPACKET = PLAYERCONNECTION.getType().getMethod("sendPacket", PACKET_CLASS);
    51. try {
    52. PACKET_PLAYER_CHAT_CONSTRUCTOR = PACKET_PLAYER_CHAT_CLASS.getConstructor(ICHATCOMP, byte.class);
    53. } catch (NoSuchMethodException e) {
    54. CHAT_MESSAGE_TYPE_CLASS = Class.forName("net.minecraft.server." + SERVER_VERSION + ".ChatMessageType");
    55. CHAT_MESSAGE_TYPE_ENUM_OBJECT = CHAT_MESSAGE_TYPE_CLASS.getEnumConstants()[2];
    56.  
    57. PACKET_PLAYER_CHAT_CONSTRUCTOR = PACKET_PLAYER_CHAT_CLASS.getConstructor(ICHATCOMP,
    58. CHAT_MESSAGE_TYPE_CLASS);
    59. }
    60.  
    61. CHATMESSAGE = Class.forName("net.minecraft.server." + SERVER_VERSION + ".ChatMessage");
    62.  
    63. CHATMESSAGE_CONSTRUCTOR = CHATMESSAGE.getConstructor(String.class, Object[].class);
    64. } catch (Exception e) {
    65. e.printStackTrace();
    66. }
    67. }
    68.  
    69. /**
    70.   * Sends the hotbar message 'message' to the player 'player'
    71.   *
    72.   * @param player
    73.   * @param message
    74.   */
    75. public static void sendHotBarMessage(Player player, String message) {
    76. try {
    77. // This creates the IChatComponentBase instance
    78. Object icb = CHATMESSAGE_CONSTRUCTOR.newInstance(message, new Object[0]);
    79. // This creates the packet
    80. Object packet;
    81. try {
    82. packet = PACKET_PLAYER_CHAT_CONSTRUCTOR.newInstance(icb, (byte) 2);
    83. } catch (Exception e) {
    84. packet = PACKET_PLAYER_CHAT_CONSTRUCTOR.newInstance(icb, CHAT_MESSAGE_TYPE_ENUM_OBJECT);
    85. }
    86. // This casts the player to a craftplayer
    87. Object craftplayerInst = CRAFTPLAYERCLASS.cast(player);
    88. // This invokes the method above.
    89. Object methodhHandle = GETHANDLE.invoke(craftplayerInst);
    90. // This gets the player's connection
    91. Object playerConnection = PLAYERCONNECTION.get(methodhHandle);
    92. // This sends the packet.
    93. SENDPACKET.invoke(playerConnection, packet);
    94. } catch (Exception e) {
    95. e.printStackTrace();
    96. }
    97. }
    98. }
    99.  
    100.  


    This class works on versions 1.8+ and higher. To use this util, create a class called "HotbarMessager" and call this method to send a hotbar message
    Code:
    HotbarMessager.sendHotBarMessage(Player, Message);
    where "Player" is the player instance and "Message" is the message you want to send.
     
    Last edited: May 23, 2018
  2. Offline

    I Al Istannen

    @Zombie_Striker
    God, you are on a rampage :D

    I am just amazed that there still is no API way for it. The first thread I found was in 2014... Or I am too dumb to find it ;)

    And maybe rename "CRAFTPLAYERCLASS" to "CRAFT_PLAYER_CLASS" and document the parameters :)

    Otherwise a nice class, maybe I find some use for it!
     
  3. Offline

    ChipDev

  4. Offline

    Zombie_Striker

    @ChipDev
    Your resource is version dependent. You have to import all those classes, which means it can only work on one version of bukkit. This uses reflection, so it works on all versions of bukkit (that support hotbar messages)
     
  5. Offline

    ChipDev

    Oooh, you implemented reflection. Well then, mine became obsolete. Nice!

    I haven't been paying attention to MC versions, I'm stuck at 1.8 ^^
     
  6. Offline

    Zombie_Striker

    @ChipDev
    Just out of curiosity, why are so many servers still on 1.8? I collected some statistics for my plugins and it seems that half of all servers with them are 1.8 or lower.
     
  7. Offline

    ChipDev

    I believe that people think PvP got ruined and some mechanics did too in 1.9+, including FPS management. I don't play anymore, but from what I heard thats why.
     
  8. Offline

    PhantomUnicorns

    @Zombie_Striker I was wondering if you could explain some of your code (All if possible)? Also could I use this as a basis for something I would like to create? I was wondering if you could explain deeper because even though I know how it works, I don't know why it works (Get me? What I'm trying to say is I know how this is working and how to do it but I don't know what it's actually doing).

    - Thanks in advance, Phantom

    EDIT: Played around a bit and figured alittle more out! It would be great if you still could explain as I'm dabbling in uncharted territory (I'm charting it little by little :D)
     
    Last edited: Jan 28, 2017
  9. Offline

    Zombie_Striker

    @PhantomUnicorns
    I just posed an update to the post. There should now be comments for each line so you can understand it better.

    If you are still confused by anything, or do not know how to modify the code, I'd recommend making a PluginDev thread (since I do not want this one to go offtopic.)
     
  10. Offline

    PhantomUnicorns

    @Zombie_Striker
    Thanks, I was wondering what is the difference between
    Code:
    Optional.of(Method).get().invoke();
    
    and
    Code:
    Method#.invoke();
    
    ? They seem to do the same thing, and when I switch one with the other there was no effect (That was noticeable)
     
  11. Offline

    Zombie_Striker

    @PhantomUnicorns
    It's actually the same. If I cared a bit more about the code not throwing an exception, I would check the optional to make sure it contains a value. If the method does not exist, that would just return a null/non-existent value instead of throwing an error.

    If you know that method exists, you can just use the Method#invoke. If the method name changes between versions/ does not exist in certain updates, use the Optional.
     
  12. Offline

    PhantomUnicorns

    Oh ok thanks!
     
  13. Offline

    i3ick

    Something seems to have broken. I'm getting a nullpointer at

    Object icb = CHATMESSAGE_CONSTRUCTOR.newInstance(message,
     
  14. Offline

    genandnic

    Same here. Any chance of a patch, @Zombie_Striker?
     
  15. Offline

    AlvinB

    @genandnic @i3ick
    I fixed it. Here's the updated version:
    Code:java
    1. import java.lang.reflect.*;
    2. import java.util.Optional;
    3.  
    4. import org.bukkit.Bukkit;
    5. import org.bukkit.entity.Player;
    6.  
    7. public class HotbarMessager {
    8.  
    9. /**
    10.   * These are the Class instances. Use these to get fields or methods for classes.
    11.   */
    12. private static Class<?> CRAFTPLAYERCLASS;
    13. private static Class<?> PACKET_PLAYER_CHAT_CLASS;
    14. private static Class<?> ICHATCOMP;
    15. private static Class<?> CHATMESSAGE;
    16. private static Class<?> PACKET_CLASS;
    17.  
    18. /**
    19.   * These are the constructors for those classes. You need these to create new objects.
    20.   */
    21. private static Constructor<?> PACKET_PLAYER_CHAT_CONSTRUCTOR;
    22. private static Constructor<?> CHATMESSAGE_CONSTRUCTOR;
    23.  
    24. /**
    25.   * This is the server version. This is how we know the server version.
    26.   */
    27. private static final String SERVER_VERSION;
    28. static {
    29. /**
    30.   * This gets the server version.
    31.   */
    32. String name = Bukkit.getServer().getClass().getName();
    33. name = name.substring(name.indexOf("craftbukkit.") + "craftbukkit.".length());
    34. name = name.substring(0, name.indexOf("."));
    35. SERVER_VERSION = name;
    36.  
    37.  
    38. try {
    39. /**
    40.   * This here sets the class fields.
    41.   */
    42. CRAFTPLAYERCLASS = Class.forName("org.bukkit.craftbukkit."
    43. + SERVER_VERSION + ".entity.CraftPlayer");
    44. PACKET_PLAYER_CHAT_CLASS = Class.forName("net.minecraft.server."
    45. + SERVER_VERSION + ".PacketPlayOutChat");
    46. PACKET_CLASS = Class.forName("net.minecraft.server."
    47. + SERVER_VERSION + ".Packet");
    48. ICHATCOMP = Class.forName("net.minecraft.server." + SERVER_VERSION
    49. + ".IChatBaseComponent");
    50. PACKET_PLAYER_CHAT_CONSTRUCTOR = Optional.of(
    51. PACKET_PLAYER_CHAT_CLASS.getConstructor(ICHATCOMP,
    52. byte.class)).get();
    53.  
    54. CHATMESSAGE = Class.forName("net.minecraft.server."
    55. + SERVER_VERSION + ".ChatMessage");
    56.  
    57. /**
    58.   * If it cannot find the constructor one way, we try to get the declared constructor.
    59.   */
    60. try {
    61. CHATMESSAGE_CONSTRUCTOR = Optional.of(
    62. CHATMESSAGE
    63. .getConstructor(String.class, Object[].class))
    64. .get();
    65. } catch (NoSuchMethodException e) {
    66. CHATMESSAGE_CONSTRUCTOR = Optional.of(
    67. CHATMESSAGE.getDeclaredConstructor(String.class,
    68. Object[].class)).get();
    69. }
    70. e.printStackTrace();
    71. }
    72. }
    73.  
    74. /**
    75.   * Sends the hotbar message 'message' to the player 'player'
    76.   * @param player
    77.   * @param message
    78.   */
    79. public static void sendHotBarMessage(Player player, String message) {
    80. try {
    81. //This creates the IChatComponentBase instance
    82. Object icb = CHATMESSAGE_CONSTRUCTOR.newInstance(message,
    83. new Object[0]);
    84.  
    85. //This creates the packet
    86. Object packet = PACKET_PLAYER_CHAT_CONSTRUCTOR.newInstance(icb,
    87. (byte) 2);
    88.  
    89. //This casts the player to a craftplayer
    90. Object craftplayerInst = CRAFTPLAYERCLASS.cast(player);
    91.  
    92. //This get's the method for craftplayer's handle
    93. Optional<Method> methodOptional = Optional.of(CRAFTPLAYERCLASS
    94. .getMethod("getHandle"));
    95.  
    96. //This invokes the method above.
    97. Object methodhHandle = methodOptional.get().invoke(craftplayerInst);
    98.  
    99. //This gets the player's connection
    100. Object playerConnection = methodhHandle.getClass()
    101. .getField("playerConnection").get(methodhHandle);
    102.  
    103. //This sends the packet.
    104. Optional.of(
    105. playerConnection.getClass().getMethod("sendPacket",
    106. PACKET_CLASS)).get()
    107. .invoke(playerConnection, packet);
    108. e.printStackTrace();
    109. }
    110. }
    111. }


    @Zombie_Striker
    The error was rather simple. When finding the "v11_1_R1" string, the index passed to the substring is calculated depending on the string as the result of the previous call, but being a chained call, the variable hadn't updated yet, so the calculations got messed up. Simply moving the calls to two different lines fixed it. I can't explain why it worked previously though.

    Also, why don't you use a reflection util? I understand not wanting several classes, but why not make it a subclass? It'd make the code way cleaner, without all the exception-catching and stuff.
     
    genandnic and Zombie_Striker like this.
  16. Offline

    Zombie_Striker

    @i3ick @genandnic @AlvinB
    I have implemented your change and updated the main post.

    I did not use the util because I wanted the code to be as small as possible and, at the time, I was practicing how to use the base-java reflection classes.
     
    genandnic likes this.
  17. Offline

    Zombie_Striker

    Updated code: Added support for 1.12+
     
    genandnic likes this.
  18. Offline

    PhantomUnicorns

    @Zombie_Striker I recommend not getting the methods and fields inside the method but staticly like you have done for the enum constant and classes
     
  19. Offline

    Zombie_Striker

  20. Offline

    AlvinB

    @Zombie_Striker
    The latest version was throwing exceptions due to the fact that you were using getDeclaringClass() incorrectly. getDeclaringClass() returns the Class that has the method/field/constructor/whatever, not what type it is. I have corrected the code to use getReturnType()/getType() instead, and this fixed the problem. Also, the constructor in ChatMessage, is public, so no need to use getDeclaredConstructor(). I have corrected this to getConstructor().
    Code:java
    1. import java.lang.reflect.*;
    2.  
    3. import org.bukkit.Bukkit;
    4. import org.bukkit.entity.Player;
    5.  
    6. public class HotbarMessager {
    7.  
    8. /**
    9.   * These are the Class instances. Use these to get fields or methods for
    10.   * classes.
    11.   */
    12. private static Class<?> CRAFTPLAYERCLASS, PACKET_PLAYER_CHAT_CLASS,
    13. ICHATCOMP, CHATMESSAGE, PACKET_CLASS, CHAT_MESSAGE_TYPE_CLASS;
    14.  
    15. private static Field PLAYERCONNECTION;
    16. private static Method GETHANDLE,SENDPACKET;
    17.  
    18.  
    19. /**
    20.   * These are the constructors for those classes. You need these to create
    21.   * new objects.
    22.   */
    23. private static Constructor<?> PACKET_PLAYER_CHAT_CONSTRUCTOR,
    24. CHATMESSAGE_CONSTRUCTOR;
    25. /**
    26.   * Used in 1.12+. Bytes are replaced with this enum
    27.   */
    28. private static Object CHAT_MESSAGE_TYPE_ENUM_OBJECT;
    29.  
    30. /**
    31.   * This is the server version. This is how we know the server version.
    32.   */
    33. private static final String SERVER_VERSION;
    34. static {
    35. // This gets the server version.
    36. String name = Bukkit.getServer().getClass().getName();
    37. name = name.substring(name.indexOf("craftbukkit.")
    38. + "craftbukkit.".length());
    39. name = name.substring(0, name.indexOf("."));
    40. SERVER_VERSION = name;
    41.  
    42. try {
    43. // This here sets the class fields.
    44. CRAFTPLAYERCLASS = Class.forName("org.bukkit.craftbukkit."
    45. + SERVER_VERSION + ".entity.CraftPlayer");
    46. PACKET_PLAYER_CHAT_CLASS = Class.forName("net.minecraft.server."
    47. + SERVER_VERSION + ".PacketPlayOutChat");
    48. PACKET_CLASS = Class.forName("net.minecraft.server."
    49. + SERVER_VERSION + ".Packet");
    50. ICHATCOMP = Class.forName("net.minecraft.server." + SERVER_VERSION
    51. + ".IChatBaseComponent");
    52. GETHANDLE = CRAFTPLAYERCLASS.getMethod("getHandle");
    53. PLAYERCONNECTION = GETHANDLE.getReturnType()
    54. .getField("playerConnection");
    55. SENDPACKET = PLAYERCONNECTION.getType().getMethod("sendPacket", PACKET_CLASS);
    56. try {
    57. PACKET_PLAYER_CHAT_CONSTRUCTOR = PACKET_PLAYER_CHAT_CLASS
    58. .getConstructor(ICHATCOMP, byte.class);
    59. } catch (NoSuchMethodException e) {
    60. CHAT_MESSAGE_TYPE_CLASS = Class.forName("net.minecraft.server."
    61. + SERVER_VERSION + ".ChatMessageType");
    62. CHAT_MESSAGE_TYPE_ENUM_OBJECT = CHAT_MESSAGE_TYPE_CLASS
    63. .getEnumConstants()[2];
    64.  
    65. PACKET_PLAYER_CHAT_CONSTRUCTOR = PACKET_PLAYER_CHAT_CLASS
    66. .getConstructor(ICHATCOMP, CHAT_MESSAGE_TYPE_CLASS);
    67. }
    68.  
    69. CHATMESSAGE = Class.forName("net.minecraft.server."
    70. + SERVER_VERSION + ".ChatMessage");
    71.  
    72. CHATMESSAGE_CONSTRUCTOR = CHATMESSAGE.getConstructor(
    73. String.class, Object[].class);
    74. } catch (Exception e) {
    75. e.printStackTrace();
    76. }
    77. }
    78.  
    79. /**
    80.   * Sends the hotbar message 'message' to the player 'player'
    81.   *
    82.   * @param player
    83.   * @param message
    84.   */
    85. public static void sendHotBarMessage(Player player, String message) {
    86. try {
    87. // This creates the IChatComponentBase instance
    88. Object icb = CHATMESSAGE_CONSTRUCTOR.newInstance(message,
    89. new Object[0]);
    90. // This creates the packet
    91. Object packet;
    92. try {
    93. packet = PACKET_PLAYER_CHAT_CONSTRUCTOR.newInstance(icb,
    94. (byte) 2);
    95. } catch (Exception e) {
    96. packet = PACKET_PLAYER_CHAT_CONSTRUCTOR.newInstance(icb,
    97. CHAT_MESSAGE_TYPE_ENUM_OBJECT);
    98. }
    99. // This casts the player to a craftplayer
    100. Object craftplayerInst = CRAFTPLAYERCLASS.cast(player);
    101. // This invokes the method above.
    102. Object methodhHandle = GETHANDLE.invoke(craftplayerInst);
    103. // This gets the player's connection
    104. Object playerConnection = PLAYERCONNECTION.get(methodhHandle);
    105. // This sends the packet.
    106. SENDPACKET
    107. .invoke(playerConnection, packet);
    108. } catch (Exception e) {
    109. e.printStackTrace();
    110. }
    111. }
    112. }
     
  21. Offline

    MightyOne

    is it ok to use this without understanding it? xD it is really useful tho
     
  22. Offline

    AlvinB

    @MightyOne
    Yes, that's the point, you can use this so you don't have to understand the messy reflection "under the hood". :)
     
    MightyOne likes this.
Thread Status:
Not open for further replies.

Share This Page