Add better item name shortening. (Fixes #112)

This commit is contained in:
Phoenix616 2018-03-12 21:01:28 +01:00
parent b22d8fd95d
commit 6e9824e6b0
5 changed files with 111 additions and 69 deletions

View File

@ -1,6 +1,8 @@
package com.Acrobot.Breeze.Utils;
import com.Acrobot.Breeze.Collection.SimpleCache;
import com.Acrobot.ChestShop.ChestShop;
import com.Acrobot.ChestShop.Configuration.Properties;
import com.google.common.collect.ImmutableMap;
import de.themoep.ShowItem.api.ShowItem;
import info.somethingodd.OddItem.OddItem;
@ -20,9 +22,7 @@ import org.json.simple.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -37,8 +37,9 @@ public class MaterialUtil {
public static final boolean LONG_NAME = true;
public static final boolean SHORT_NAME = false;
private static final Map<String, Material> MATERIAL_CACHE = new HashMap<String, Material>();
public static final short MAXIMUM_SIGN_LETTERS = 15;
private static final SimpleCache<String, Material> MATERIAL_CACHE = new SimpleCache<>(Properties.CACHE_SIZE);
/**
* Checks if the itemStack is empty or null
@ -81,27 +82,45 @@ public class MaterialUtil {
* @return Material found
*/
public static Material getMaterial(String name) {
String formatted = name.replaceAll(" |_", "").toUpperCase();
String formatted = name.toUpperCase();
if (MATERIAL_CACHE.containsKey(formatted)) {
return MATERIAL_CACHE.get(formatted);
Material material = MATERIAL_CACHE.get(formatted);
if (material != null) {
return material;
}
Material material = Material.matchMaterial(name);
material = Material.matchMaterial(name);
if (material != null) {
MATERIAL_CACHE.put(formatted, material);
return material;
}
String[] nameParts = name.toUpperCase().split(" ");
short length = Short.MAX_VALUE;
for (Material currentMaterial : Material.values()) {
String matName = currentMaterial.name();
String matName = currentMaterial.toString();
if (matName.length() < length && matName.replace("_", "").startsWith(formatted)) {
if (matName.length() < length && matName.startsWith(formatted)) {
length = (short) matName.length();
material = currentMaterial;
} else if (nameParts.length > 1) {
String[] matParts = matName.split("_");
if (nameParts.length == matParts.length) {
boolean matched = true;
for (int i = 0; i < matParts.length; i++) {
if (!matParts[i].startsWith(nameParts[i])) {
matched = false;
break;
}
}
if (matched) {
material = currentMaterial;
break;
}
}
}
}
@ -117,7 +136,7 @@ public class MaterialUtil {
* @return ItemStack's name
*/
public static String getName(ItemStack itemStack) {
return getName(itemStack, LONG_NAME);
return getName(itemStack, 0);
}
/**
@ -126,7 +145,9 @@ public class MaterialUtil {
* @param itemStack ItemStack to name
* @param showDataValue Should we also show the data value?
* @return ItemStack's name
* @deprecated Use {@link #getName(ItemStack, int)}
*/
@Deprecated
public static String getName(ItemStack itemStack, boolean showDataValue) {
String dataName = DataValue.name(itemStack);
@ -144,23 +165,80 @@ public class MaterialUtil {
* @return ItemStack's name
*/
public static String getSignName(ItemStack itemStack) {
StringBuilder name = new StringBuilder(15);
return getName(itemStack, MAXIMUM_SIGN_LETTERS);
}
/**
* Returns item's name, with a maximum length
*
* @param itemStack ItemStack to name
* @param maxLength The max length that the name should have; 0 or below if it should be unlimited
* @return ItemStack's name
*/
public static String getName(ItemStack itemStack, int maxLength) {
String alias = Odd.getAlias(itemStack);
String itemName = alias != null ? alias : itemStack.getType().name();
itemName = StringUtil.capitalizeFirstLetter(itemName, '_');
name.append(itemName);
if (itemStack.getDurability() != 0) {
name.append(':').append(itemStack.getDurability());
String itemName = alias != null ? alias : itemStack.getType().toString();
String data = DataValue.name(itemStack);
String durability = "";
if (data == null) {
if (itemStack.getDurability() != 0) {
durability = ":" + itemStack.getDurability();
}
}
data = data != null ? data + "_" : "";
String metaData = "";
if (itemStack.hasItemMeta()) {
name.append('#').append(Metadata.getItemCode(itemStack));
metaData = "#" + Metadata.getItemCode(itemStack);
}
String code = data + itemName + durability + metaData;
if (maxLength > 0 && code.length() > maxLength) {
String[] itemParts = itemName.split("_");
int exceeding = code.length() - maxLength;
int shortestIndex = 0;
int longestIndex = 0;
for (int i = 0; i < itemParts.length; i++) {
if (itemParts[longestIndex].length() < itemParts[i].length()) {
longestIndex = i;
}
if (itemParts[shortestIndex].length() > itemParts[i].length()) {
shortestIndex = i;
}
}
if (itemParts[longestIndex].length() - itemParts[shortestIndex].length() > exceeding) {
itemParts[longestIndex] = itemParts[longestIndex].substring(0, itemParts[longestIndex].length() - exceeding);
} else {
for (int i = itemParts.length - 1; i >= 0 && exceeding > 0; i--) {
int remove = 0;
if (itemParts[i].length() > itemParts[shortestIndex].length()) {
remove = itemParts[i].length() - itemParts[shortestIndex].length();
}
if (remove > exceeding) {
remove = exceeding;
}
itemParts[i] = itemParts[i].substring(0, itemParts[i].length() - remove);
exceeding -= remove;
}
while (exceeding > 0) {
for (int i = itemParts.length - 1; i >= 0 && exceeding > 0; i--) {
itemParts[i] = itemParts[i].substring(0, itemParts[i].length() - 1);
exceeding--;
}
}
}
code = data + String.join("_", itemParts) + durability + metaData;
}
return name.toString();
code = StringUtil.capitalizeFirstLetter(code, '_');
ItemStack codeItem = getItem(code);
if (!equals(itemStack, codeItem)) {
throw new IllegalArgumentException("Cannot generate code for item " + itemStack + " with maximum length of " + maxLength);
}
return code;
}
/**
@ -361,10 +439,10 @@ public class MaterialUtil {
public static class Metadata {
/**
* Returns the ItemStack represented by this code
* Returns the ItemMeta represented by this code
*
* @param code Code representing the item
* @return Item represented by code
* @param code Code representing the ItemMeta
* @return ItemMeta represented by code
*/
public static ItemMeta getFromCode(String code) {
ItemStack item = ChestShop.getItemDatabase().getFromCode(code);

View File

@ -35,11 +35,9 @@ public class ItemInfo implements CommandExecutor {
return false;
}
String durability = getDurability(item);
String metadata = getMetadata(item);
sender.sendMessage(Messages.prefix(iteminfo));
sender.sendMessage(getNameAndID(item) + durability + metadata + ChatColor.WHITE);
sender.sendMessage(ChatColor.WHITE + "Full Name: " + ChatColor.GRAY + MaterialUtil.getName(item));
sender.sendMessage(ChatColor.WHITE + "Shop Sign: " + ChatColor.GRAY + MaterialUtil.getSignName(item));
ItemInfoEvent event = new ItemInfoEvent(sender, item);
ChestShop.callEvent(event);
@ -48,9 +46,7 @@ public class ItemInfo implements CommandExecutor {
}
private static String getNameAndID(ItemStack item) {
String itemName = MaterialUtil.getName(item);
return ChatColor.GRAY + itemName;
return MaterialUtil.getName(item);
}
private static String getDurability(ItemStack item) {

View File

@ -11,7 +11,7 @@ public class Properties {
public static boolean TURN_OFF_UPDATES = false;
@PrecededBySpace
@ConfigurationComment("How large should the internal uuid and name caches be?")
@ConfigurationComment("How large should the internal caches be?")
public static int CACHE_SIZE = 1000;
@PrecededBySpace

View File

@ -9,7 +9,7 @@ import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import static com.Acrobot.Breeze.Utils.InventoryUtil.mergeSimilarStacks;
import static com.Acrobot.Breeze.Utils.MaterialUtil.getSignName;
import static com.Acrobot.Breeze.Utils.MaterialUtil.getName;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.BUY;
/**
@ -26,7 +26,7 @@ public class TransactionLogger implements Listener {
StringBuilder items = new StringBuilder(50);
for (ItemStack item : mergeSimilarStacks(event.getStock())) {
items.append(item.getAmount()).append(' ').append(getSignName(item));
items.append(item.getAmount()).append(' ').append(getName(item));
}
String message = String.format(template,

View File

@ -1,7 +1,6 @@
package com.Acrobot.ChestShop.Listeners.PreShopCreation;
import com.Acrobot.Breeze.Utils.MaterialUtil;
import com.Acrobot.Breeze.Utils.StringUtil;
import com.Acrobot.ChestShop.Configuration.Messages;
import com.Acrobot.ChestShop.Configuration.Properties;
import com.Acrobot.ChestShop.Events.PreShopCreationEvent;
@ -26,17 +25,12 @@ import static com.Acrobot.ChestShop.Signs.ChestShopSign.AUTOFILL_CODE;
* @author Acrobot
*/
public class ItemChecker implements Listener {
private static final short MAXIMUM_SIGN_LETTERS = 15;
@EventHandler(priority = EventPriority.LOWEST)
public static void onPreShopCreation(PreShopCreationEvent event) {
String itemCode = event.getSignLine(ITEM_LINE);
ItemStack item = MaterialUtil.getItem(itemCode);
if (Odd.getFromString(itemCode) != null) {
return; // The OddItem name is OK
}
if (item == null) {
if (Properties.ALLOW_AUTO_ITEM_FILL && itemCode.equals(AUTOFILL_CODE)) {
boolean foundItem = false;
@ -44,7 +38,6 @@ public class ItemChecker implements Listener {
if (chest != null) {
for (ItemStack stack : chest.getInventory().getContents()) {
if (!MaterialUtil.isEmpty(stack)) {
item = stack;
itemCode = MaterialUtil.getSignName(stack);
event.setSignLine(ITEM_LINE, itemCode);
@ -66,36 +59,11 @@ public class ItemChecker implements Listener {
return;
}
}
String metadata = getMetadata(itemCode);
String longName = MaterialUtil.getName(item);
if (longName.length() <= (MAXIMUM_SIGN_LETTERS - metadata.length())) {
if (isSameItem(longName + metadata, item)) {
String itemName = StringUtil.capitalizeFirstLetter(longName);
event.setSignLine(ITEM_LINE, itemName + metadata);
return;
}
}
String code = MaterialUtil.getName(item, SHORT_NAME);
String[] parts = itemCode.split("(?=:|-|#)", 2);
String data = (parts.length > 1 ? parts[1] : "");
if (code.length() > (MAXIMUM_SIGN_LETTERS - data.length())) {
code = code.substring(0, MAXIMUM_SIGN_LETTERS - data.length());
}
if (!isSameItem(code + data, item)) {
if (itemCode.length() > MAXIMUM_SIGN_LETTERS) {
event.setOutcome(INVALID_ITEM);
return;
}
code = StringUtil.capitalizeFirstLetter(code);
event.setSignLine(ITEM_LINE, code + data);
}
private static boolean isSameItem(String newCode, ItemStack item) {