1+ package dev .kitteh .cardboardbox ;
2+
3+ import dev .kitteh .cardboardbox .api .Box ;
4+ import org .bukkit .Bukkit ;
5+ import org .bukkit .Material ;
6+ import org .bukkit .enchantments .Enchantment ;
7+ import org .bukkit .inventory .ItemStack ;
8+ import org .bukkit .inventory .meta .ItemMeta ;
9+ import org .bukkit .plugin .java .JavaPlugin ;
10+
11+ import java .util .Arrays ;
12+ import java .util .regex .Matcher ;
13+ import java .util .regex .Pattern ;
14+
15+ public class CardboardBox {
16+ private static boolean ready = false ;
17+ private static boolean modernPaper = false ;
18+ private static Exception exception ;
19+
20+ private static Box chosenBox ;
21+
22+ static {
23+ init ();
24+ }
25+
26+ private static void init () {
27+ try {
28+ ItemStack .class .getDeclaredMethod ("deserializeBytes" , byte [].class );
29+ ItemStack .class .getDeclaredMethod ("serializeAsBytes" );
30+ modernPaper = true ;
31+ ready = true ;
32+ return ;
33+ } catch (Exception ignored ) {
34+ }
35+ try {
36+ int mcVersion = getMcVersion ();
37+ if (mcVersion < 808 ) {
38+ JavaPlugin .getProvidingPlugin (CardboardBox .class ).getLogger ().warning ("CardboardBox could not identify Minecraft version." );
39+ ready = false ;
40+ }
41+ if (mcVersion >= 2100 ) {
42+ chosenBox = getBox ("v1_21" );
43+ } else if (mcVersion == 2006 ) {
44+ chosenBox = getBox ("v1_20_6" );
45+ } else {
46+ chosenBox = new dev .kitteh .cardboardbox .pre_v1_20_6 .Box ();
47+ }
48+ ItemStack itemStack = new ItemStack (Material .DIAMOND_SWORD );
49+ ItemMeta meta = itemStack .getItemMeta ();
50+ meta .addEnchant (Enchantment .KNOCKBACK , 3 , false );
51+ meta .setDisplayName ("Meow meow!" );
52+ meta .setLore (Arrays .asList ("New" , "line" , " here" ));
53+ itemStack .setItemMeta (meta );
54+ if (!itemStack .equals (chosenBox .deserializeItem (chosenBox .serializeItem (itemStack )))) {
55+ throw new IllegalStateException ("Failed to deserialize serialized content properly" );
56+ }
57+ ready = true ;
58+ } catch (Exception e ) {
59+ exception = e ;
60+ }
61+ }
62+
63+ private static Box getBox (String ver ) throws Exception {
64+ return (Box ) Class .forName (CardboardBox .class .getPackage ().getName () + "." + ver + ".Box" ).getConstructor ().newInstance ();
65+ }
66+
67+ private static int getMcVersion () {
68+ Pattern versionPattern = Pattern .compile ("1\\ .(\\ d{1,2})(?:\\ .(\\ d{1,2}))?" );
69+ Matcher versionMatcher = versionPattern .matcher (Bukkit .getVersion ());
70+
71+ int mcVersion = 0 ;
72+ if (versionMatcher .find ()) {
73+ try {
74+ int minor = Integer .parseInt (versionMatcher .group (1 ));
75+ String patchS = versionMatcher .group (2 );
76+ int patch = (patchS == null || patchS .isEmpty ()) ? 0 : Integer .parseInt (patchS );
77+ mcVersion = (minor * 100 ) + patch ;
78+ } catch (NumberFormatException ignored ) {
79+ }
80+ }
81+ return mcVersion ;
82+ }
83+
84+ /**
85+ * Gets if Cardboard Box will just use Paper's built-in functionality.
86+ *
87+ * @return true if the built-in methods exist, eliminating stress
88+ */
89+ public static boolean isModernPaperSupport () {
90+ return modernPaper ;
91+ }
92+
93+ /**
94+ * Gets if Cardboard Box is ready to work, or failed to initialize.
95+ *
96+ * @return true if ready
97+ */
98+ public static boolean isReady () {
99+ return ready ;
100+ }
101+
102+ /**
103+ * Gets the exception showing the failure to load, if not ready.
104+ *
105+ * @return exception if failed to load properly
106+ */
107+ public static Exception getException () {
108+ return exception ;
109+ }
110+
111+ /**
112+ * Serializes an ItemStack to bytes. Will store air and null the same, as
113+ * just a single byte of 0x0.
114+ *
115+ * @param item item to serialize
116+ * @return bytes of the item serialized
117+ * @throws IllegalStateException if CardboardBox failed to initialize
118+ * (check with {@link #isReady()})
119+ * @throws RuntimeException if serialization failed for any reason
120+ */
121+ public static byte [] serializeItem (ItemStack item ) {
122+ if (!ready ) {
123+ throw new IllegalStateException ("Cardboard Box failed to initialize. Cannot serialize without risk." , exception );
124+ }
125+ if (item == null || item .getType () == Material .AIR ) {
126+ return new byte []{0x0 };
127+ }
128+ if (modernPaper ) {
129+ return item .serializeAsBytes ();
130+ }
131+ return chosenBox .serializeItem (item );
132+ }
133+
134+ /**
135+ * Deserializes an ItemStack previously serialized by Cardboard Box. Will
136+ * return air for a null or empty array of data.
137+ *
138+ * @param data data to deserialize
139+ * @return the ItemStack
140+ * @throws IllegalArgumentException if the stored item's version is
141+ * greater than the current server data version
142+ * @throws IllegalStateException if CardboardBox failed to initialize
143+ * (check with {@link #isReady()})
144+ * @throws RuntimeException if deserialization failed for any reason
145+ */
146+ public static ItemStack deserializeItem (byte [] data ) {
147+ if (!ready ) {
148+ throw new IllegalStateException ("Cardboard Box failed to initialize. Cannot serialize without risk." , exception );
149+ }
150+ if (data == null || data .length == 0 || (data .length == 1 && data [0 ] == 0x0 )) {
151+ return new ItemStack (Material .AIR );
152+ }
153+ if (modernPaper ) {
154+ return ItemStack .deserializeBytes (data );
155+ }
156+ return chosenBox .deserializeItem (data );
157+ }
158+ }
0 commit comments