Better handling of inventory serialization errors
This commit is contained in:
@@ -41,6 +41,7 @@ import org.bukkit.inventory.ItemStack;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@@ -235,10 +236,19 @@ public class InvCommand extends Command {
|
|||||||
}
|
}
|
||||||
if (entry.getAction().equals(EntryAction.INVENTORY)) {
|
if (entry.getAction().equals(EntryAction.INVENTORY)) {
|
||||||
PlayerInventoryRecord inv_;
|
PlayerInventoryRecord inv_;
|
||||||
|
byte[] blob;
|
||||||
try {
|
try {
|
||||||
inv_ = InvSerialization.toPlayerInventory(entry.getBlob());
|
blob = entry.getBlob();
|
||||||
} catch (Exception e1) {
|
} 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);
|
plugin.print(e1);
|
||||||
sender.sendLang(Language.L.ERROR);
|
sender.sendLang(Language.L.ERROR);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class InvSerialization {
|
public class InvSerialization {
|
||||||
|
|
||||||
@@ -111,40 +113,29 @@ public class InvSerialization {
|
|||||||
if (player == null) {
|
if (player == null) {
|
||||||
return 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(),
|
return playerToByteArray(new PlayerInventoryRecord(player.getInventory().getStorageContents(),
|
||||||
player.getInventory().getArmorContents(), player.getInventory().getExtraContents(),
|
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 {
|
private static byte[] playerToByteArray(PlayerInventoryRecord record, String playerName, IntSet[] skip, int maxRecursion) throws IOException {
|
||||||
if (record == null) {
|
if (record == null) return null;
|
||||||
return null;
|
if (maxRecursion <= 0) return null;
|
||||||
}
|
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
try (BukkitObjectOutputStream stream = new BukkitObjectOutputStream(byteArrayOutputStream)) {
|
try (BukkitObjectOutputStream stream = new BukkitObjectOutputStream(byteArrayOutputStream)) {
|
||||||
|
|
||||||
stream.writeInt(record.storage().length);
|
try {
|
||||||
for (int i = 0; i < record.storage().length; i++) {
|
writeInventory(stream, record.storage(), playerName, "main inventory", skip[0]);
|
||||||
ItemStack item = record.storage()[i];
|
writeInventory(stream, record.armor(), playerName, "armor", skip[1]);
|
||||||
write(stream, item, playerName, "main inventory", i);
|
writeInventory(stream, record.extra(), playerName, "offhand/extra", skip[2]);
|
||||||
}
|
writeInventory(stream, record.ender(), playerName, "ender chest", skip[3]);
|
||||||
|
} catch (ItemSerializationException e) {
|
||||||
stream.writeInt(record.armor().length);
|
return playerToByteArray(record, playerName, skip, maxRecursion - 1);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.writeInt(record.exp());
|
stream.writeInt(record.exp());
|
||||||
@@ -156,17 +147,40 @@ public class InvSerialization {
|
|||||||
|
|
||||||
private static final Map<String, Long> spamMap = new HashMap<>();
|
private static final Map<String, Long> 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<Integer> {
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Integer> skip) throws IOException {
|
||||||
try {
|
try {
|
||||||
stream.writeObject(item);
|
stream.writeObject(item);
|
||||||
} catch (Throwable e) {
|
} 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() + ")";
|
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);
|
spamMap.values().removeIf(l -> System.currentTimeMillis() - l > 60000L);
|
||||||
if (!spamMap.containsKey(msg)) {
|
if (!spamMap.containsKey(msg)) {
|
||||||
spamMap.put(msg, System.currentTimeMillis());
|
spamMap.put(msg, System.currentTimeMillis());
|
||||||
AuxProtectAPI.warning(msg);
|
AuxProtectAPI.warning(msg);
|
||||||
|
AuxProtectAPI.print(e);
|
||||||
}
|
}
|
||||||
stream.writeObject(null);
|
throw new ItemSerializationException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@@ -18,6 +18,6 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<jars>${env.USERPROFILE}/eclipse-workspace/jars</jars>
|
<jars>${env.USERPROFILE}/eclipse-workspace/jars</jars>
|
||||||
<project.build.sourceEncoding>UTF8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF8</project.build.sourceEncoding>
|
||||||
<revision>1.3.4-pre1</revision>
|
<revision>1.3.4-pre2</revision>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
Reference in New Issue
Block a user