diff --git a/AuxProtect_Core/src/main/java/dev/heliosares/auxprotect/core/commands/InvCommand.java b/AuxProtect_Core/src/main/java/dev/heliosares/auxprotect/core/commands/InvCommand.java index 9e395d5..2e6ebff 100644 --- a/AuxProtect_Core/src/main/java/dev/heliosares/auxprotect/core/commands/InvCommand.java +++ b/AuxProtect_Core/src/main/java/dev/heliosares/auxprotect/core/commands/InvCommand.java @@ -41,6 +41,7 @@ import org.bukkit.inventory.ItemStack; import java.sql.SQLException; import java.time.LocalDateTime; import java.util.Arrays; +import java.util.Base64; import java.util.List; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; @@ -235,10 +236,19 @@ public class InvCommand extends Command { } if (entry.getAction().equals(EntryAction.INVENTORY)) { PlayerInventoryRecord inv_; + byte[] blob; try { - inv_ = InvSerialization.toPlayerInventory(entry.getBlob()); + blob = entry.getBlob(); } catch (Exception e1) { - plugin.warning("Error serializing inventory lookup"); + plugin.warning("Error getting blob from inventory entry"); + plugin.print(e1); + sender.sendLang(Language.L.ERROR); + return; + } + try { + inv_ = InvSerialization.toPlayerInventory(blob); + } catch (Exception e1) { + plugin.warning("Error deserializing inventory: " + Base64.getEncoder().encodeToString(blob)); plugin.print(e1); sender.sendLang(Language.L.ERROR); return; diff --git a/AuxProtect_Core/src/main/java/dev/heliosares/auxprotect/utils/InvSerialization.java b/AuxProtect_Core/src/main/java/dev/heliosares/auxprotect/utils/InvSerialization.java index e9403a8..8fecfca 100644 --- a/AuxProtect_Core/src/main/java/dev/heliosares/auxprotect/utils/InvSerialization.java +++ b/AuxProtect_Core/src/main/java/dev/heliosares/auxprotect/utils/InvSerialization.java @@ -14,7 +14,9 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; public class InvSerialization { @@ -111,40 +113,29 @@ public class InvSerialization { if (player == null) { return null; } + IntSet[] skip = new IntSet[4]; + for (int i = 0; i < skip.length; i++) { + skip[i] = new IntSet(); + } return playerToByteArray(new PlayerInventoryRecord(player.getInventory().getStorageContents(), player.getInventory().getArmorContents(), player.getInventory().getExtraContents(), - player.getEnderChest().getContents(), Experience.getTotalExp(player)), player.getName()); + player.getEnderChest().getContents(), Experience.getTotalExp(player)), player.getName(), skip, 100); } - public static byte[] playerToByteArray(PlayerInventoryRecord record, String playerName) throws IOException { - if (record == null) { - return null; - } + private static byte[] playerToByteArray(PlayerInventoryRecord record, String playerName, IntSet[] skip, int maxRecursion) throws IOException { + if (record == null) return null; + if (maxRecursion <= 0) return null; + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try (BukkitObjectOutputStream stream = new BukkitObjectOutputStream(byteArrayOutputStream)) { - stream.writeInt(record.storage().length); - for (int i = 0; i < record.storage().length; i++) { - ItemStack item = record.storage()[i]; - write(stream, item, playerName, "main inventory", i); - } - - stream.writeInt(record.armor().length); - for (int i = 0; i < record.armor().length; i++) { - ItemStack item = record.armor()[i]; - write(stream, item, playerName, "armor", i); - } - - stream.writeInt(record.extra().length); - for (int i = 0; i < record.extra().length; i++) { - ItemStack item = record.extra()[i]; - write(stream, item, playerName, "offhand/extra", i); - } - - stream.writeInt(record.ender().length); - for (int i = 0; i < record.ender().length; i++) { - ItemStack item = record.ender()[i]; - write(stream, item, playerName, "ender chest", i); + try { + writeInventory(stream, record.storage(), playerName, "main inventory", skip[0]); + writeInventory(stream, record.armor(), playerName, "armor", skip[1]); + writeInventory(stream, record.extra(), playerName, "offhand/extra", skip[2]); + writeInventory(stream, record.ender(), playerName, "ender chest", skip[3]); + } catch (ItemSerializationException e) { + return playerToByteArray(record, playerName, skip, maxRecursion - 1); } stream.writeInt(record.exp()); @@ -156,17 +147,40 @@ public class InvSerialization { private static final Map spamMap = new HashMap<>(); - private static void write(BukkitObjectOutputStream stream, ItemStack item, String playerName, String inventoryName, int index) throws IOException { + private static void writeInventory(BukkitObjectOutputStream stream, ItemStack[] items, String playerName, String inventoryName, IntSet skip) throws IOException { + stream.writeInt(items.length); + for (int i = 0; i < items.length; i++) { + if (skip.contains(i)) { + stream.writeObject(null); + continue; + } + ItemStack item = items[i]; + writeItem(stream, item, playerName, inventoryName, i, skip); + } + } + + private static class IntSet extends HashSet { + } + + private static class ItemSerializationException extends IOException { + public ItemSerializationException(Throwable cause) { + super(cause); + } + } + + private static void writeItem(BukkitObjectOutputStream stream, ItemStack item, String playerName, String inventoryName, int index, Set skip) throws IOException { try { stream.writeObject(item); } catch (Throwable e) { + skip.add(index); String msg = "Failed to serialize item in " + inventoryName + ", slot " + index + " of " + playerName + ". This is not an issue with AuxProtect, it is Bukkit failing to serialize the item correctly. The item will be logged as an empty slot. (" + e.getClass().getName() + ": " + e.getMessage() + ")"; spamMap.values().removeIf(l -> System.currentTimeMillis() - l > 60000L); if (!spamMap.containsKey(msg)) { spamMap.put(msg, System.currentTimeMillis()); AuxProtectAPI.warning(msg); + AuxProtectAPI.print(e); } - stream.writeObject(null); + throw new ItemSerializationException(e); } } diff --git a/pom.xml b/pom.xml index 04dc15a..0343a36 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,6 @@ ${env.USERPROFILE}/eclipse-workspace/jars UTF8 - 1.3.4-pre1 + 1.3.4-pre2 \ No newline at end of file