Last active
October 26, 2024 16:41
-
-
Save graywolf336/8153678 to your computer and use it in GitHub Desktop.
Serialize and deserialize the player's inventory, including armor and content.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Converts the player inventory to a String array of Base64 strings. First string is the content and second string is the armor. | |
* | |
* @param playerInventory to turn into an array of strings. | |
* @return Array of strings: [ main content, armor content ] | |
* @throws IllegalStateException | |
*/ | |
public static String[] playerInventoryToBase64(PlayerInventory playerInventory) throws IllegalStateException { | |
//get the main content part, this doesn't return the armor | |
String content = toBase64(playerInventory); | |
String armor = itemStackArrayToBase64(playerInventory.getArmorContents()); | |
return new String[] { content, armor }; | |
} | |
/** | |
* | |
* A method to serialize an {@link ItemStack} array to Base64 String. | |
* | |
* <p /> | |
* | |
* Based off of {@link #toBase64(Inventory)}. | |
* | |
* @param items to turn into a Base64 String. | |
* @return Base64 string of the items. | |
* @throws IllegalStateException | |
*/ | |
public static String itemStackArrayToBase64(ItemStack[] items) throws IllegalStateException { | |
try { | |
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | |
BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream); | |
// Write the size of the inventory | |
dataOutput.writeInt(items.length); | |
// Save every element in the list | |
for (int i = 0; i < items.length; i++) { | |
dataOutput.writeObject(items[i]); | |
} | |
// Serialize that array | |
dataOutput.close(); | |
return Base64Coder.encodeLines(outputStream.toByteArray()); | |
} catch (Exception e) { | |
throw new IllegalStateException("Unable to save item stacks.", e); | |
} | |
} | |
/** | |
* A method to serialize an inventory to Base64 string. | |
* | |
* <p /> | |
* | |
* Special thanks to Comphenix in the Bukkit forums or also known | |
* as aadnk on GitHub. | |
* | |
* <a href="https://gist.github.com/aadnk/8138186">Original Source</a> | |
* | |
* @param inventory to serialize | |
* @return Base64 string of the provided inventory | |
* @throws IllegalStateException | |
*/ | |
public static String toBase64(Inventory inventory) throws IllegalStateException { | |
try { | |
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | |
BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream); | |
// Write the size of the inventory | |
dataOutput.writeInt(inventory.getSize()); | |
// Save every element in the list | |
for (int i = 0; i < inventory.getSize(); i++) { | |
dataOutput.writeObject(inventory.getItem(i)); | |
} | |
// Serialize that array | |
dataOutput.close(); | |
return Base64Coder.encodeLines(outputStream.toByteArray()); | |
} catch (Exception e) { | |
throw new IllegalStateException("Unable to save item stacks.", e); | |
} | |
} | |
/** | |
* | |
* A method to get an {@link Inventory} from an encoded, Base64, string. | |
* | |
* <p /> | |
* | |
* Special thanks to Comphenix in the Bukkit forums or also known | |
* as aadnk on GitHub. | |
* | |
* <a href="https://gist.github.com/aadnk/8138186">Original Source</a> | |
* | |
* @param data Base64 string of data containing an inventory. | |
* @return Inventory created from the Base64 string. | |
* @throws IOException | |
*/ | |
public static Inventory fromBase64(String data) throws IOException { | |
try { | |
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(data)); | |
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream); | |
Inventory inventory = Bukkit.getServer().createInventory(null, dataInput.readInt()); | |
// Read the serialized inventory | |
for (int i = 0; i < inventory.getSize(); i++) { | |
inventory.setItem(i, (ItemStack) dataInput.readObject()); | |
} | |
dataInput.close(); | |
return inventory; | |
} catch (ClassNotFoundException e) { | |
throw new IOException("Unable to decode class type.", e); | |
} | |
} | |
/** | |
* Gets an array of ItemStacks from Base64 string. | |
* | |
* <p /> | |
* | |
* Base off of {@link #fromBase64(String)}. | |
* | |
* @param data Base64 string to convert to ItemStack array. | |
* @return ItemStack array created from the Base64 string. | |
* @throws IOException | |
*/ | |
public static ItemStack[] itemStackArrayFromBase64(String data) throws IOException { | |
try { | |
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(data)); | |
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream); | |
ItemStack[] items = new ItemStack[dataInput.readInt()]; | |
// Read the serialized inventory | |
for (int i = 0; i < items.length; i++) { | |
items[i] = (ItemStack) dataInput.readObject(); | |
} | |
dataInput.close(); | |
return items; | |
} catch (ClassNotFoundException e) { | |
throw new IOException("Unable to decode class type.", e); | |
} | |
} |
Thank you
Using ObjectInputStream is highly discouraged and should be avoided whenever possible due to major security risks. This will also have (continuously) worse(ning) performance compared to https://jd.papermc.io/paper/1.20/org/bukkit/inventory/ItemStack.html#serializeAsBytes() and https://jd.papermc.io/paper/1.20/org/bukkit/inventory/ItemStack.html#deserializeBytes(byte[]), e.g.:
public static String serialize(ItemStack[] items) {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
DataOutput output = new DataOutputStream(outputStream);
output.writeInt(items.length);
for (ItemStack item : items) {
if (item == null) {
// Ensure the correct order by including empty/null items
// Simply remove the write line if you don't want this
output.writeInt(0);
continue;
}
byte[] bytes = item.serializeAsBytes();
output.writeInt(bytes.length);
output.write(bytes);
}
return Base64Coder.encodeLines(outputStream.toByteArray()); // Base64 encoding is not strictly needed
} catch (IOException e) {
throw new RuntimeException("Error while writing itemstack", e);
}
}
public static ItemStack[] deserialize(String encodedItems) {
byte[] bytes = Base64Coder.decodeLines(encodedItems); // Base64 encoding is not strictly needed
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
DataInputStream input = new DataInputStream(inputStream);
int count = input.readInt();
ItemStack[] items = new ItemStack[count];
for (int i = 0; i < count; i++) {
int length = input.readInt();
if (length == 0) {
// Empty item, keep entry as null
continue;
}
byte[] itemBytes = new byte[length];
input.read(itemBytes);
items[i] = ItemStack.deserializeBytes(itemBytes);
}
return items;
} catch (IOException e) {
throw new RuntimeException("Error while reading itemstack", e);
}
}
Or if you for some reason really need to support those few % of lost souls still using Spigot on even semi recent version, using internals is still better than the object streams and Spigot item serialization (though the linked example will still perform worse than Paper API)
License?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
.