CC-Tweaked/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java

163 lines
6.2 KiB
Java

/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.details;
import com.google.gson.JsonParseException;
import dan200.computercraft.shared.platform.PlatformHelper;
import dan200.computercraft.shared.platform.RegistryWrappers;
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.EnchantedBookItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import javax.annotation.Nullable;
import java.util.*;
/**
* Data providers for items.
*/
public class ItemDetails {
public static <T extends Map<? super String, Object>> T fillBasicSafe(T data, ItemStack stack) {
data.put("name", DetailHelpers.getId(RegistryWrappers.ITEMS, stack.getItem()));
data.put("count", stack.getCount());
return data;
}
public static void fillBasic(Map<? super String, Object> data, ItemStack stack) {
fillBasicSafe(data, stack);
var hash = NBTUtil.getNBTHash(stack.getTag());
if (hash != null) data.put("nbt", hash);
}
public static void fill(Map<? super String, Object> data, ItemStack 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().isBarVisible(stack)) {
data.put("durability", stack.getItem().getBarWidth(stack) / 13.0);
}
data.put("tags", DetailHelpers.getTags(stack.getTags()));
data.put("itemGroups", getItemGroups(stack));
var tag = stack.getTag();
if (tag != null && tag.contains("display", Tag.TAG_COMPOUND)) {
var displayTag = tag.getCompound("display");
if (displayTag.contains("Lore", Tag.TAG_LIST)) {
var loreTag = displayTag.getList("Lore", Tag.TAG_STRING);
data.put("lore", loreTag.stream()
.map(ItemDetails::parseTextComponent)
.filter(Objects::nonNull)
.map(Component::getString)
.toList());
}
}
/*
* Used to hide some data from ItemStack tooltip.
* @see https://minecraft.gamepedia.com/Tutorials/Command_NBT_tags
* @see ItemStack#getTooltip
*/
var hideFlags = tag != null ? tag.getInt("HideFlags") : 0;
var enchants = getAllEnchants(stack, hideFlags);
if (!enchants.isEmpty()) data.put("enchantments", enchants);
if (tag != null && tag.getBoolean("Unbreakable") && (hideFlags & 4) == 0) {
data.put("unbreakable", true);
}
}
@Nullable
private static Component parseTextComponent(Tag x) {
try {
return Component.Serializer.fromJson(x.getAsString());
} catch (JsonParseException e) {
return null;
}
}
/**
* Retrieve all item groups an item stack pertains to.
*
* @param stack Stack to analyse
* @return A filled list that contains pairs of item group IDs and their display names.
*/
private static List<Map<String, Object>> getItemGroups(ItemStack stack) {
return CreativeModeTabs.allTabs().stream()
.filter(x -> x.shouldDisplay() && x.getType() == CreativeModeTab.Type.CATEGORY && x.contains(stack))
.map(group -> {
Map<String, Object> groupData = new HashMap<>(2);
var id = PlatformHelper.get().getCreativeTabId(group);
if (id != null) groupData.put("id", id.toString());
groupData.put("displayName", group.getDisplayName().getString());
return groupData;
})
.toList();
}
/**
* 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.
*/
private static List<Map<String, Object>> getAllEnchants(ItemStack stack, int hideFlags) {
var enchants = new ArrayList<Map<String, Object>>(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 EnchantmentHelper
*/
private static void addEnchantments(ListTag rawEnchants, ArrayList<Map<String, Object>> enchants) {
if (rawEnchants.isEmpty()) return;
enchants.ensureCapacity(enchants.size() + rawEnchants.size());
for (var entry : EnchantmentHelper.deserializeEnchantments(rawEnchants).entrySet()) {
var enchantment = entry.getKey();
var level = entry.getValue();
var enchant = new HashMap<String, Object>(3);
enchant.put("name", DetailHelpers.getId(RegistryWrappers.ENCHANTMENTS, enchantment));
enchant.put("level", level);
enchant.put("displayName", enchantment.getFullname(level).getString());
enchants.add(enchant);
}
}
}