172 lines
5.9 KiB
Java
172 lines
5.9 KiB
Java
/*
|
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
|
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
|
* Send enquiries to dratcliffe@gmail.com
|
|
*/
|
|
package dan200.computercraft.shared.peripheral.generic.data;
|
|
|
|
import com.google.gson.JsonParseException;
|
|
import dan200.computercraft.shared.util.NBTUtil;
|
|
import net.minecraft.enchantment.Enchantment;
|
|
import net.minecraft.enchantment.EnchantmentHelper;
|
|
import net.minecraft.item.EnchantedBookItem;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.CompoundNBT;
|
|
import net.minecraft.nbt.INBT;
|
|
import net.minecraft.nbt.ListNBT;
|
|
import net.minecraft.util.text.ITextComponent;
|
|
import net.minecraftforge.common.util.Constants;
|
|
|
|
import javax.annotation.Nonnull;
|
|
import javax.annotation.Nullable;
|
|
import java.util.*;
|
|
import java.util.stream.Collectors;
|
|
|
|
/**
|
|
* Data providers for items.
|
|
*/
|
|
public class ItemData
|
|
{
|
|
@Nonnull
|
|
public static <T extends Map<? super String, Object>> 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 extends Map<? super String, Object>> 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;
|
|
}
|
|
|
|
@Nonnull
|
|
public static <T extends Map<? super String, Object>> T fill( @Nonnull T data, @Nonnull ItemStack stack )
|
|
{
|
|
if( stack.isEmpty() ) return data;
|
|
|
|
fillBasic( data, stack );
|
|
|
|
data.put( "displayName", stack.getHoverName().getString() );
|
|
data.put( "maxCount", stack.getMaxStackSize() );
|
|
|
|
if( stack.isDamageableItem() )
|
|
{
|
|
data.put( "damage", stack.getDamageValue() );
|
|
data.put( "maxDamage", stack.getMaxDamage() );
|
|
}
|
|
|
|
if( stack.getItem().showDurabilityBar( stack ) )
|
|
{
|
|
data.put( "durability", stack.getItem().getDurabilityForDisplay( stack ) );
|
|
}
|
|
|
|
data.put( "tags", DataHelpers.getTags( stack.getItem().getTags() ) );
|
|
|
|
CompoundNBT tag = stack.getTag();
|
|
if( tag != null && tag.contains( "display", Constants.NBT.TAG_COMPOUND ) )
|
|
{
|
|
CompoundNBT displayTag = tag.getCompound( "display" );
|
|
if( displayTag.contains( "Lore", Constants.NBT.TAG_LIST ) )
|
|
{
|
|
ListNBT loreTag = displayTag.getList( "Lore", Constants.NBT.TAG_STRING );
|
|
data.put( "lore", loreTag.stream()
|
|
.map( ItemData::parseTextComponent )
|
|
.filter( Objects::nonNull )
|
|
.map( ITextComponent::getString )
|
|
.collect( Collectors.toList() ) );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Used to hide some data from ItemStack tooltip.
|
|
* @see https://minecraft.gamepedia.com/Tutorials/Command_NBT_tags
|
|
* @see ItemStack#getTooltip
|
|
*/
|
|
int hideFlags = tag != null ? tag.getInt( "HideFlags" ) : 0;
|
|
|
|
List<Map<String, Object>> enchants = getAllEnchants( stack, hideFlags );
|
|
if( !enchants.isEmpty() ) data.put( "enchantments", enchants );
|
|
|
|
if( tag != null && tag.getBoolean( "Unbreakable" ) && (hideFlags & 4) == 0 )
|
|
{
|
|
data.put( "unbreakable", true );
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
@Nullable
|
|
private static ITextComponent parseTextComponent( @Nonnull INBT x )
|
|
{
|
|
try
|
|
{
|
|
return ITextComponent.Serializer.fromJson( x.getAsString() );
|
|
}
|
|
catch( JsonParseException e )
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieve all visible enchantments from given stack. Try to follow all tooltip rules : order and visibility.
|
|
*
|
|
* @param stack Stack to analyse
|
|
* @param hideFlags An int used as bit field to provide visibility rules.
|
|
* @return A filled list that contain all visible enchantments.
|
|
*/
|
|
@Nonnull
|
|
private static List<Map<String, Object>> getAllEnchants( @Nonnull ItemStack stack, int hideFlags )
|
|
{
|
|
ArrayList<Map<String, Object>> enchants = new ArrayList<>( 0 );
|
|
|
|
if( stack.getItem() instanceof EnchantedBookItem && (hideFlags & 32) == 0 )
|
|
{
|
|
addEnchantments( EnchantedBookItem.getEnchantments( stack ), enchants );
|
|
}
|
|
|
|
if( stack.isEnchanted() && (hideFlags & 1) == 0 )
|
|
{
|
|
/*
|
|
* Mimic the EnchantmentHelper.getEnchantments(ItemStack stack) behavior without special case for Enchanted book.
|
|
* I'll do that to have the same data than ones displayed in tooltip.
|
|
* @see EnchantmentHelper.getEnchantments(ItemStack stack)
|
|
*/
|
|
addEnchantments( stack.getEnchantmentTags(), enchants );
|
|
}
|
|
|
|
return enchants;
|
|
}
|
|
|
|
/**
|
|
* Converts a Mojang enchant map to a Lua list.
|
|
*
|
|
* @param rawEnchants The raw NBT list of enchantments
|
|
* @param enchants The enchantment map to add it to.
|
|
* @see net.minecraft.enchantment.EnchantmentHelper
|
|
*/
|
|
private static void addEnchantments( @Nonnull ListNBT rawEnchants, @Nonnull ArrayList<Map<String, Object>> enchants )
|
|
{
|
|
if( rawEnchants.isEmpty() ) return;
|
|
|
|
enchants.ensureCapacity( enchants.size() + rawEnchants.size() );
|
|
|
|
for( Map.Entry<Enchantment, Integer> entry : EnchantmentHelper.deserializeEnchantments( rawEnchants ).entrySet() )
|
|
{
|
|
Enchantment enchantment = entry.getKey();
|
|
Integer level = entry.getValue();
|
|
HashMap<String, Object> enchant = new HashMap<>( 3 );
|
|
enchant.put( "name", DataHelpers.getId( enchantment ) );
|
|
enchant.put( "level", level );
|
|
enchant.put( "displayName", enchantment.getFullname( level ).getString() );
|
|
enchants.add( enchant );
|
|
}
|
|
}
|
|
}
|