Skip to content

Commit 85a2039

Browse files
committed
Massively improve ReflectionHelper
1 parent d41da42 commit 85a2039

File tree

1 file changed

+84
-118
lines changed

1 file changed

+84
-118
lines changed

src/main/java/me/rayzr522/jsonmessage/JSONMessage.java

Lines changed: 84 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.google.gson.JsonElement;
88
import com.google.gson.JsonObject;
99
import com.google.gson.JsonPrimitive;
10+
1011
import org.bukkit.Bukkit;
1112
import org.bukkit.ChatColor;
1213
import org.bukkit.entity.Player;
@@ -15,14 +16,17 @@
1516
import java.lang.invoke.MethodHandles;
1617
import java.lang.reflect.Constructor;
1718
import java.lang.reflect.Field;
18-
import java.lang.reflect.InvocationTargetException;
1919
import java.lang.reflect.Method;
20-
import java.util.*;
20+
import java.util.ArrayList;
21+
import java.util.List;
22+
import java.util.Objects;
23+
import java.util.UUID;
24+
import java.util.Vector;
2125

2226
/**
2327
* This is a complete JSON message builder class. To create a new JSONMessage do
2428
* {@link #create(String)}
25-
*
29+
*
2630
* @author Rayzr
2731
*/
2832
@SuppressWarnings({"WeakerAccess", "unused"})
@@ -160,8 +164,8 @@ public String toLegacy() {
160164
*/
161165
public void send(Player... players) {
162166
if (ReflectionHelper.MAJOR_VER >= 16) {
163-
ReflectionHelper.sendTextPacket(toString(), players);
164-
return;
167+
// ReflectionHelper.sendTextPacket(toString(), players);
168+
// return;
165169
}
166170

167171
ReflectionHelper.sendPacket(ReflectionHelper.createTextPacket(toString()), players);
@@ -226,9 +230,9 @@ public JSONMessage color(String color) {
226230
* Sets the color of the current message part.
227231
* <br>If the provided color is a hex color ({@code #rrggbb}) but the major version of MC is older than 1.16 will the provided
228232
* default ChatColor be used instead.
229-
*
233+
*
230234
* @param color The color to set
231-
* @param def The default ChatColor to use, when MC version is older than 1.16
235+
* @param def The default ChatColor to use, when MC version is older than 1.16
232236
* @return This {@link JSONMessage} instance
233237
*/
234238
public JSONMessage color(String color, ChatColor def) {
@@ -242,14 +246,14 @@ public JSONMessage color(String color, ChatColor def) {
242246
/**
243247
* Sets the font of the current message part.
244248
* <br>When this is used on versions older than 1.16 will this do nothing.
245-
*
249+
*
246250
* @param font The font to set
247251
* @return This {@link JSONMessage} instance
248252
*/
249253
public JSONMessage font(String font) {
250254
if (ReflectionHelper.MAJOR_VER < 16)
251255
return this;
252-
256+
253257
last().setFont(font);
254258
return this;
255259
}
@@ -627,6 +631,9 @@ private static class ReflectionHelper {
627631
private static Class<?> craftPlayer;
628632
private static Constructor<?> chatComponentText;
629633
private static Class<?> packetPlayOutChat;
634+
private static Field packetPlayOutChatComponent;
635+
private static Field packetPlayOutChatMessageType;
636+
private static Field packetPlayOutChatUuid;
630637
private static Class<?> packetPlayOutTitle;
631638
private static Class<?> iChatBaseComponent;
632639
private static Class<?> titleAction;
@@ -646,9 +653,7 @@ private static class ReflectionHelper {
646653
version = split[split.length - 1];
647654

648655
try {
649-
SETUP = true;
650-
651-
MAJOR_VER = getVersion();
656+
MAJOR_VER = Integer.parseInt(version.split("_")[1]);
652657

653658
craftPlayer = getClass("{obc}.entity.CraftPlayer");
654659
Method getHandle = craftPlayer.getMethod("getHandle");
@@ -672,6 +677,9 @@ private static class ReflectionHelper {
672677
STRING_TO_CHAT = MethodHandles.lookup().unreflect(stringToChat);
673678

674679
packetPlayOutChat = getClass("{nms}.PacketPlayOutChat");
680+
packetPlayOutChatComponent = getField(packetPlayOutChat, "a");
681+
packetPlayOutChatMessageType = getField(packetPlayOutChat, "b");
682+
packetPlayOutChatUuid = MAJOR_VER >= 16 ? getField(packetPlayOutChat, "c") : null;
675683
packetPlayOutTitle = getClass("{nms}.PacketPlayOutTitle");
676684

677685
titleAction = getClass("{nms}.PacketPlayOutTitle$EnumTitleAction");
@@ -686,17 +694,16 @@ private static class ReflectionHelper {
686694
enumActionbarMessage = getChatMessageType.invoke(null, (byte) 2);
687695
}
688696

697+
SETUP = true;
689698
} catch (Exception e) {
690699
e.printStackTrace();
691700
SETUP = false;
692701
}
693-
694702
}
695703

696704
static void sendPacket(Object packet, Player... players) {
697-
if (!SETUP) {
698-
throw new IllegalStateException("ReflectionHelper is not set up!");
699-
}
705+
assertIsSetup();
706+
700707
if (packet == null) {
701708
return;
702709
}
@@ -712,102 +719,80 @@ static void sendPacket(Object packet, Player... players) {
712719

713720
}
714721

715-
private static void setType(Object object, byte type) {
716-
if (MAJOR_VER < 12) {
717-
set("b", object, type);
718-
return;
719-
}
720-
721-
switch (type) {
722-
case 1:
723-
set("b", object, enumChatMessage);
724-
break;
725-
case 2:
726-
set("b", object, enumActionbarMessage);
727-
break;
728-
default:
729-
throw new IllegalArgumentException("type must be 1 or 2");
730-
}
731-
}
732-
733722
static Object createActionbarPacket(String message) {
734-
if (!SETUP) {
735-
throw new IllegalStateException("ReflectionHelper is not set up!");
736-
}
723+
assertIsSetup();
724+
737725
Object packet = createTextPacket(message);
738726
setType(packet, (byte) 2);
739727
return packet;
740728
}
741729

742730
static Object createTextPacket(String message) {
743-
if (!SETUP) {
744-
throw new IllegalStateException("ReflectionHelper is not set up!");
745-
}
731+
assertIsSetup();
732+
746733
try {
747734
Object packet = packetPlayOutChat.newInstance();
748-
set("a", packet, fromJson(message));
735+
setFieldValue(packetPlayOutChatComponent, packet, fromJson(message));
736+
setFieldValue(packetPlayOutChatUuid, packet, UUID.randomUUID());
749737
setType(packet, (byte) 1);
750738
return packet;
751739
} catch (Exception e) {
752740
e.printStackTrace();
753741
return null;
754742
}
755-
756743
}
757744

758-
static void sendTextPacket(String message, Player... players) {
745+
static Object createTitlePacket(String message) {
746+
assertIsSetup();
747+
759748
try {
760-
for (Player player : players) {
761-
Class chatTypeClass = getClass("{nms}.ChatMessageType");
762-
Constructor<?> constructor = packetPlayOutChat.getConstructor(getClass("{nms}.IChatBaseComponent"), chatTypeClass, UUID.class);
763-
Object packet = constructor.newInstance(fromJson(message), Enum.valueOf(chatTypeClass, "CHAT"), player.getUniqueId());
764-
765-
Object handler = player.getClass().getMethod("getHandle").invoke(player);
766-
Object playerConnection = handler.getClass().getField("playerConnection").get(handler);
767-
playerConnection.getClass().getMethod("sendPacket", getClass("{nms}.Packet")).invoke(playerConnection, packet);
768-
}
769-
} catch (IllegalArgumentException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException | InvocationTargetException | InstantiationException | ClassNotFoundException e) {
749+
return packetPlayOutTitle.getConstructor(titleAction, iChatBaseComponent).newInstance(enumActionTitle, fromJson(message));
750+
} catch (Exception e) {
770751
e.printStackTrace();
752+
return null;
771753
}
772754
}
773755

774-
static Object createTitlePacket(String message) {
775-
if (!SETUP) {
776-
throw new IllegalStateException("ReflectionHelper is not set up!");
777-
}
756+
static Object createTitleTimesPacket(int fadeIn, int stay, int fadeOut) {
757+
assertIsSetup();
758+
778759
try {
779-
return packetPlayOutTitle.getConstructor(titleAction, iChatBaseComponent).newInstance(enumActionTitle, fromJson(message));
760+
return packetPlayOutTitle.getConstructor(int.class, int.class, int.class).newInstance(fadeIn, stay, fadeOut);
780761
} catch (Exception e) {
781762
e.printStackTrace();
782763
return null;
783764
}
784-
785765
}
786766

787767
static Object createSubtitlePacket(String message) {
788-
if (!SETUP) {
789-
throw new IllegalStateException("ReflectionHelper is not set up!");
790-
}
768+
assertIsSetup();
769+
791770
try {
792771
return packetPlayOutTitle.getConstructor(titleAction, iChatBaseComponent).newInstance(enumActionSubtitle, fromJson(message));
793772
} catch (Exception e) {
794773
e.printStackTrace();
795774
return null;
796775
}
797-
798776
}
799777

800-
static Object createTitleTimesPacket(int fadeIn, int stay, int fadeOut) {
801-
if (!SETUP) {
802-
throw new IllegalStateException("ReflectionHelper is not set up!");
803-
}
804-
try {
805-
return packetPlayOutTitle.getConstructor(int.class, int.class, int.class).newInstance(fadeIn, stay, fadeOut);
806-
} catch (Exception e) {
807-
e.printStackTrace();
808-
return null;
778+
private static void setType(Object chatPacket, byte type) {
779+
assertIsSetup();
780+
781+
if (MAJOR_VER < 12) {
782+
setFieldValue(packetPlayOutChatMessageType, chatPacket, type);
783+
return;
809784
}
810785

786+
switch (type) {
787+
case 1:
788+
setFieldValue(packetPlayOutChatMessageType, chatPacket, enumChatMessage);
789+
break;
790+
case 2:
791+
setFieldValue(packetPlayOutChatMessageType, chatPacket, enumActionbarMessage);
792+
break;
793+
default:
794+
throw new IllegalArgumentException("type must be 1 or 2");
795+
}
811796
}
812797

813798
/**
@@ -817,9 +802,8 @@ static Object createTitleTimesPacket(int fadeIn, int stay, int fadeOut) {
817802
* @return The chat component
818803
*/
819804
static Object componentText(String message) {
820-
if (!SETUP) {
821-
throw new IllegalStateException("ReflectionHelper is not set up!");
822-
}
805+
assertIsSetup();
806+
823807
try {
824808
return chatComponentText.newInstance(message);
825809
} catch (Exception e) {
@@ -836,9 +820,8 @@ static Object componentText(String message) {
836820
* @return The object representing the text in JSON form, or <code>null</code> if something went wrong converting the String to JSON data
837821
*/
838822
static Object fromJson(String json) {
839-
if (!SETUP) {
840-
throw new IllegalStateException("ReflectionHelper is not set up!");
841-
}
823+
assertIsSetup();
824+
842825
if (!json.trim().startsWith("{")) {
843826
return componentText(json);
844827
}
@@ -849,60 +832,45 @@ static Object fromJson(String json) {
849832
e.printStackTrace();
850833
return null;
851834
}
852-
853835
}
854836

855-
/**
856-
* Returns a class with the given package and name. This method replaces <code>{nms}</code> with <code>net.minecraft.server.[version]</code> and <code>{obc}</code> with <code>org.bukkit.craft.[version]</code>
857-
* <br>
858-
* <br>
859-
* Example:
860-
*
861-
* <pre>
862-
* Class<?> entityPlayer = ReflectionHelper.getClass("{nms}.EntityPlayer");
863-
* </pre>
864-
*
865-
* @param path The path to the {@link Class}
866-
* @return The class
867-
* @throws ClassNotFoundException If the class was not found
868-
*/
869-
static Class<?> getClass(String path) throws ClassNotFoundException {
837+
private static void assertIsSetup() {
870838
if (!SETUP) {
871-
throw new IllegalStateException("ReflectionHelper is not set up!");
839+
throw new IllegalStateException("JSONMessage.ReflectionHelper is not set up yet!");
872840
}
841+
}
842+
843+
private static Class<?> getClass(String path) throws ClassNotFoundException {
873844
return Class.forName(path.replace("{nms}", "net.minecraft.server." + version).replace("{obc}", "org.bukkit.craftbukkit." + version));
874845
}
875846

876-
/**
877-
* Sets a field with the given name on an object to the value specified
878-
*
879-
* @param field The name of the field to change
880-
* @param obj The object to change the field of
881-
* @param value The new value to set
882-
*/
883-
static void set(String field, Object obj, Object value) {
847+
private static void setFieldValue(Field field, Object instance, Object value) {
848+
if (field == null) {
849+
// useful for fields that might not exist
850+
return;
851+
}
852+
884853
try {
885-
Field f = obj.getClass().getDeclaredField(field);
886-
f.setAccessible(true);
887-
f.set(obj, value);
888-
} catch (Exception e) {
854+
field.set(instance, value);
855+
} catch (IllegalAccessException e) {
889856
e.printStackTrace();
890857
}
891858
}
892859

893-
static int getVersion() {
894-
if (!SETUP) {
895-
throw new IllegalStateException("ReflectionHelper is not set up!");
896-
}
860+
private static Field getField(Class<?> classObject, String fieldName) {
897861
try {
898-
return Integer.parseInt(version.split("_")[1]);
899-
} catch (NumberFormatException e) {
862+
Field field = classObject.getDeclaredField(fieldName);
863+
field.setAccessible(true);
864+
return field;
865+
} catch (NoSuchFieldException e) {
900866
e.printStackTrace();
901-
return 10;
867+
return null;
902868
}
903-
904869
}
905870

871+
private static int getVersion() {
872+
return MAJOR_VER;
873+
}
906874
}
907875

908876
/**
@@ -1013,12 +981,11 @@ public String getColorValue() {
1013981

1014982
/**
1015983
* @return The color
1016-
*
1017984
* @deprecated Use {@link #getColorValue()} instead
1018985
*/
1019986
@Deprecated
1020987
public ChatColor getColor() {
1021-
if(this.color.startsWith("#") && ReflectionHelper.MAJOR_VER < 16)
988+
if (this.color.startsWith("#") && ReflectionHelper.MAJOR_VER < 16)
1022989
throw new IllegalStateException("Custom Hex colors can only be used in Minecraft 1.16 or newer!");
1023990

1024991
try {
@@ -1030,7 +997,6 @@ public ChatColor getColor() {
1030997

1031998
/**
1032999
* @param color The color to set
1033-
*
10341000
* @deprecated Use {@link #setColor(String)} instead
10351001
*/
10361002
@Deprecated

0 commit comments

Comments
 (0)