diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index 1a422487e..a2a39f599 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -7,6 +7,8 @@ package dan200.computercraft.shared.peripheral.generic.data; import com.google.gson.JsonParseException; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.item.EnchantedBookItem; @@ -22,13 +24,29 @@ import java.util.*; import java.util.stream.Collectors; +/** + * Data providers for items. + * + * We guard using {@link ComputerCraft#genericPeripheral} in several places, as advanced functionality should not be + * exposed for {@code turtle.getItemDetail} when generic peripehrals are disabled. + */ public class ItemData { @Nonnull - public static > T fillBasic( @Nonnull T data, @Nonnull ItemStack stack ) + public static > T fillBasicSafe( @Nonnull T data, @Nonnull ItemStack stack ) { data.put( "name", DataHelpers.getId( stack.getItem() ) ); data.put( "count", stack.getCount() ); + + return data; + } + + @Nonnull + public static > T fillBasic( @Nonnull T data, @Nonnull ItemStack stack ) + { + fillBasicSafe( data, stack ); + String hash = NBTUtil.getNBTHash( stack.getTag() ); + if( hash != null ) data.put( "nbt", hash ); return data; } @@ -55,6 +73,8 @@ public static > T fill( @Nonnull T data, @ data.put( "tags", DataHelpers.getTags( stack.getItem().getTags() ) ); + if( !ComputerCraft.genericPeripheral ) return data; + CompoundNBT tag = stack.getTag(); if( tag != null && tag.contains( "display", Constants.NBT.TAG_COMPOUND ) ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 260c9423f..57040804c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -605,7 +605,7 @@ private Object[] getItemDetail( int slot, boolean detailed ) Map table = detailed ? ItemData.fill( new HashMap<>(), stack ) - : ItemData.fillBasic( new HashMap<>(), stack ); + : ItemData.fillBasicSafe( new HashMap<>(), stack ); TurtleActionEvent event = new TurtleInspectItemEvent( turtle, stack, table, detailed ); if( MinecraftForge.EVENT_BUS.post( event ) ) return new Object[] { false, event.getFailureMessage() }; diff --git a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java index 4f4b9cfba..006effe07 100644 --- a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java @@ -5,9 +5,19 @@ */ package dan200.computercraft.shared.util; +import dan200.computercraft.ComputerCraft; import net.minecraft.nbt.*; import net.minecraftforge.common.util.Constants; +import org.apache.commons.codec.binary.Hex; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; @@ -159,4 +169,46 @@ public static Object[] decodeObjects( CompoundNBT tag ) } return objects; } + + @Nullable + public static String getNBTHash( @Nullable CompoundNBT tag ) + { + if( tag == null ) return null; + + try + { + MessageDigest digest = MessageDigest.getInstance( "MD5" ); + DataOutput output = new DataOutputStream( new DigestOutputStream( digest ) ); + CompressedStreamTools.write( tag, output ); + byte[] hash = digest.digest(); + return new String( Hex.encodeHex( hash ) ); + } + catch( NoSuchAlgorithmException | IOException e ) + { + ComputerCraft.log.error( "Cannot hash NBT", e ); + return null; + } + } + + private static class DigestOutputStream extends OutputStream + { + private final MessageDigest digest; + + private DigestOutputStream( MessageDigest digest ) + { + this.digest = digest; + } + + @Override + public void write( @Nonnull byte[] b, int off, int len ) + { + digest.update( b, off, len ); + } + + @Override + public void write( int b ) + { + digest.update( (byte) b ); + } + } }