SpongePowered / Sponge

The SpongeAPI implementation targeting vanilla Minecraft and 3rd party platforms.
MIT License
391 stars 211 forks source link

ItemStack serialization fails for some modded items #2637

Open alexstaeding opened 4 years ago

alexstaeding commented 4 years ago

I am currently running

Issue Description There are a few modded blocks that do not serialize correctly. So far I have found a few blocks from mekanism an ae2 that don't work. I am using DataFormats.JSON.write(container) and Sponge.getDataManager().deserialize(ItemStack.class, DataFormats.JSON.read(json)) for serialization/deserialization.

To Reproduce

  1. Create empty SF server and forge client
  2. Download Mekanism-1.12.2-9.8.3.390.jar and place in mods folder on both server and client
  3. Place SF inside mods folder
  4. Make TestJar (see below tests)
  5. Start and join the server

(Make sure your inventory is empty before starting each test)

Test 1

  1. Place any vanilla item in your inventory
  2. Run /sertest
  3. "Returned itemstack" should appear in chat

Works normally

Test 2

  1. Place an Elite Combining Factory in your inventory
  2. Run /sertest
  3. "Returned itemstack" should appear in chat

Works normally

Test 3

  1. Place an Elite Combining Factory on the ground
  2. Mine with a pickaxe and pick it up
  3. Throw away the pickaxe, you should only have the Elite Combining Factory in your inventory
  4. Run /sertest
  5. "Error occurred while executing command: Unable to translate object to JSON: [B@5a9af188" appears in chat and this error shows up in console:

Does not work

Make TestJar This is the code I used to test this bug. Making an empty sponge project and just pasting this class in should work. Build and put in the server's mods folder.

@Plugin(id = "inventoryserializationtest")
public class InventorySerializationTest {
    @Inject
    private Logger logger;
    @Listener
    public void onInit(GameInitializationEvent event) {
        logger.info("Registering command");
        CommandSpec command = CommandSpec.builder().executor((source, context) -> {
            if (!(source instanceof Player)) {
                source.sendMessage(Text.of(TextColors.RED, "Run as player"));
                return CommandResult.empty();
            }

            // get itemstack from player inventory
            Player player = (Player) source;
            Optional<ItemStack> itemStack = player.getInventory().poll(1);
            if (!itemStack.isPresent()) {
                player.sendMessage(Text.of(TextColors.RED, "Inventory is empty"));
                return CommandResult.empty();
            }

            // save itemstack into json
            String json;
            try {
                json = DataFormats.JSON.write(itemStack.get().toContainer());
            } catch (IOException e) {
                e.printStackTrace();
                player.sendMessage(Text.of(TextColors.RED, "Serialization failed"));
                return CommandResult.empty();
            }

            // turn json back into itemstack
            ItemStack itemStackResult;
            try {
                itemStackResult = Sponge.getDataManager()
                    .deserialize(ItemStack.class, DataFormats.JSON.read(json))
                    .orElseThrow(() -> new IllegalStateException("Result not present"));
            } catch (IOException e) {
                e.printStackTrace();
                player.sendMessage(Text.of(TextColors.RED, "Deserialization failed"));
                return CommandResult.empty();
            }

            // return itemstack to player
            InventoryTransactionResult result = player.getInventory().offer(itemStackResult);
            if (result.getType().equals(InventoryTransactionResult.Type.SUCCESS)) {
                player.sendMessage(Text.of(TextColors.GREEN, "Returned itemstack"));
            } else {
                player.sendMessage(Text.of(TextColors.RED, "Returning of itemstack failed"));
            }
            return CommandResult.success();
        }).build();
        Sponge.getCommandManager().register(this, command, "sertest");
    }
}
jacoballen1 commented 4 years ago

From what I can tell this is because there is no way to serialize a byte array (mekanism stores the machine internal config as a byte array). This is also an issue with AE2 memory cards which use a byte array for the color (which is used for linking the card to a specific P2P tunnel)

gabizou commented 4 years ago

This is more of a failure for our translator not handling byte arrays, which should be supported just fine.