-
-
Save graywolf336/8153678 to your computer and use it in GitHub Desktop.
/** | |
* 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 a lot. I saved a lot of time thanks to this class.
Amazing! Got null exeptions when using the FromBase64 method but that is probably just me. Otherwise great!
I got a OptionalDataException on fromBase64 https://gist.github.com/graywolf336/8153678#file-bukkitserialization-java-L107 any fix?
Fixed for 1.16 (may work in other versions, but I haven't tested):
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.util.io.BukkitObjectInputStream;
import org.bukkit.util.io.BukkitObjectOutputStream;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class SerializeInventory {
/**
* Converts the player inventory to a Base64 encoded string.
*
* @param playerInventory to turn into an array of strings.
* @return string with serialized Inventory
* @throws IllegalStateException
*/
public static String playerInventoryToBase64(PlayerInventory playerInventory) throws IllegalStateException {
// This contains contents, armor and offhand (contents are indexes 0 - 35, armor 36 - 39, offhand - 40)
return itemStackArrayToBase64(playerInventory.getContents());
}
/**
*
* A method to serialize an {@link ItemStack} array to Base64 String.
*
* @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);
dataOutput.writeInt(items.length);
for (ItemStack item : items) {
if (item != null) {
dataOutput.writeObject(item.serializeAsBytes());
} else {
dataOutput.writeObject(null);
}
}
dataOutput.close();
return Base64Coder.encodeLines(outputStream.toByteArray());
} catch (Exception e) {
throw new IllegalStateException("Unable to save item stacks.", e);
}
}
/**
* Gets an array of ItemStacks from Base64 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()];
for (int Index = 0; Index < items.length; Index++) {
byte[] stack = (byte[]) dataInput.readObject();
if (stack != null) {
items[Index] = ItemStack.deserializeBytes(stack);
} else {
items[Index] = null;
}
}
dataInput.close();
return items;
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}
}
}
Fixed for 1.16 (may work in other versions, but I haven't tested):
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.util.io.BukkitObjectInputStream; import org.bukkit.util.io.BukkitObjectOutputStream; import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; public class SerializeInventory { /** * Converts the player inventory to a Base64 encoded string. * * @param playerInventory to turn into an array of strings. * @return string with serialized Inventory * @throws IllegalStateException */ public static String playerInventoryToBase64(PlayerInventory playerInventory) throws IllegalStateException { // This contains contents, armor and offhand (contents are indexes 0 - 35, armor 36 - 39, offhand - 40) return itemStackArrayToBase64(playerInventory.getContents()); } /** * * A method to serialize an {@link ItemStack} array to Base64 String. * * @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); dataOutput.writeInt(items.length); for (ItemStack item : items) { if (item != null) { dataOutput.writeObject(item.serializeAsBytes()); } else { dataOutput.writeObject(null); } } dataOutput.close(); return Base64Coder.encodeLines(outputStream.toByteArray()); } catch (Exception e) { throw new IllegalStateException("Unable to save item stacks.", e); } } /** * Gets an array of ItemStacks from Base64 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()]; for (int Index = 0; Index < items.length; Index++) { byte[] stack = (byte[]) dataInput.readObject(); if (stack != null) { items[Index] = ItemStack.deserializeBytes(stack); } else { items[Index] = null; } } dataInput.close(); return items; } catch (ClassNotFoundException e) { throw new IOException("Unable to decode class type.", e); } } }
I.... don't think that'll work. As far as I'm aware; there is no such method as serializeAsBytes
or deserializeBytes
Closest I know of is deserialize
and serialize
Oh. I haven't realized that those functions are PaperMC exclusive... Well... Using them makes output string shorter. If you are using Spigot / Bukkit you can exchange them (serializeAsBytes()
, and deserializeBytes()
) for serialize()
and deserialize()
, and some variable types from byte[]
to Map<String, Object>
, and it should work as intended.
Will it be possible to encode the inventory to a single line? I have tried removing the newlines but for some reason that causes the string to be empty. I am sure I am doing something wrong, but I have no idea what. If you want to see my code just ask for it, but I don't think it's useful.
That is a great method, but i don't want to storage the inventory slots that have AIR or are null
Does Somebody know what to do?
That is a great method, but i don't want to storage the inventory slots that have AIR or are null
Does Somebody know what to do?
Just filter the items
You're awesome.
you are now my lord
Hi, would you mind adding the MIT or similar permissive license to this? There are many projects using it(because it is awesome) but it is unclear if the default gist license allows redistribution.
thanks, this works really well
Hey, does anybody know if this works with Spigot 1.16.5?
@MarcusSlover yeah, it does.
@iKstruuh thanks
Author, thanks. Works with Purpur-1.18.2.
This saved me so much work trying to make my own serializer 0-0
Thanks graywolf!
Kiss in the left and right hollow of the knee
is it works on spigot 1.19.3?
nvm i tested its still work on 1.19.3 with a spigot api
Still works on 1.19.4 Spigot/Paper.
In addition to that, here for those who wants to encode / decode single itemstacks:
/**
* Gets one {@link ItemStack} from Base64 string.
*
* @param data Base64 string to convert to {@link ItemStack}.
* @return {@link ItemStack} created from the Base64 string.
* @throws IOException
*/
public static ItemStack itemStackFromBase64(String data) throws IOException {
try {
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decode(data));
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
ItemStack item;
// Read the serialized inventory
item = (ItemStack) dataInput.readObject();
dataInput.close();
return item;
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}
}
/**
* A method to serialize one {@link ItemStack} to Base64 String.
*
* @param item to turn into a Base64 String.
* @return Base64 string of the item.
* @throws IllegalStateException
*/
public static String itemStackToBase64(ItemStack item) throws IllegalStateException {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream);
// Save every element
dataOutput.writeObject(item);
// Serialize that array
dataOutput.close();
return new String(Base64Coder.encode(outputStream.toByteArray()));
} catch (Exception e) {
throw new IllegalStateException("Unable to save item stacks.", e);
}
}
Fixed for 1.16 (may work in other versions, but I haven't tested):
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.util.io.BukkitObjectInputStream; import org.bukkit.util.io.BukkitObjectOutputStream; import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; public class SerializeInventory { /** * Converts the player inventory to a Base64 encoded string. * * @param playerInventory to turn into an array of strings. * @return string with serialized Inventory * @throws IllegalStateException */ public static String playerInventoryToBase64(PlayerInventory playerInventory) throws IllegalStateException { // This contains contents, armor and offhand (contents are indexes 0 - 35, armor 36 - 39, offhand - 40) return itemStackArrayToBase64(playerInventory.getContents()); } /** * * A method to serialize an {@link ItemStack} array to Base64 String. * * @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); dataOutput.writeInt(items.length); for (ItemStack item : items) { if (item != null) { dataOutput.writeObject(item.serializeAsBytes()); } else { dataOutput.writeObject(null); } } dataOutput.close(); return Base64Coder.encodeLines(outputStream.toByteArray()); } catch (Exception e) { throw new IllegalStateException("Unable to save item stacks.", e); } } /** * Gets an array of ItemStacks from Base64 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()]; for (int Index = 0; Index < items.length; Index++) { byte[] stack = (byte[]) dataInput.readObject(); if (stack != null) { items[Index] = ItemStack.deserializeBytes(stack); } else { items[Index] = null; } } dataInput.close(); return items; } catch (ClassNotFoundException e) { throw new IOException("Unable to decode class type.", e); } } }
Thanks!
Still works on 1.19.4 Spigot/Paper.
In addition to that, here for those who wants to encode / decode single itemstacks:
/** * Gets one {@link ItemStack} from Base64 string. * * @param data Base64 string to convert to {@link ItemStack}. * @return {@link ItemStack} created from the Base64 string. * @throws IOException */ public static ItemStack itemStackFromBase64(String data) throws IOException { try { ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decode(data)); BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream); ItemStack item; // Read the serialized inventory item = (ItemStack) dataInput.readObject(); dataInput.close(); return item; } catch (ClassNotFoundException e) { throw new IOException("Unable to decode class type.", e); } } /** * A method to serialize one {@link ItemStack} to Base64 String. * * @param item to turn into a Base64 String. * @return Base64 string of the item. * @throws IllegalStateException */ public static String itemStackToBase64(ItemStack item) throws IllegalStateException { try { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream); // Save every element dataOutput.writeObject(item); // Serialize that array dataOutput.close(); return new String(Base64Coder.encode(outputStream.toByteArray())); } catch (Exception e) { throw new IllegalStateException("Unable to save item stacks.", e); } }
And you, my friend, are a true hero
hello, i have this problem on 1.20.2
java.lang.IllegalArgumentException: Length of Base64 encoded input string is not a multiple of 4.
.
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?
Absolute Chad