Merge branch '1.12' into 1.13

# Conflicts:
#	src/main/java/com/Acrobot/Breeze/Utils/MaterialUtil.java
#	src/test/java/com/Acrobot/Breeze/Tests/MaterialTest.java
This commit is contained in:
Phoenix616 2018-09-09 14:47:32 +01:00
commit 54b3b6966c
5 changed files with 91 additions and 36 deletions

View File

@ -31,6 +31,9 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.Acrobot.Breeze.Utils.StringUtil.getMinecraftCharWidth;
import static com.Acrobot.Breeze.Utils.StringUtil.getMinecraftStringWidth;
/** /**
* @author Acrobot * @author Acrobot
*/ */
@ -40,7 +43,13 @@ public class MaterialUtil {
public static final boolean LONG_NAME = true; public static final boolean LONG_NAME = true;
public static final boolean SHORT_NAME = false; public static final boolean SHORT_NAME = false;
/**
* @deprecated Use {@link MaterialUtil#MAXIMUM_SIGN_WIDTH}
*/
@Deprecated
public static final short MAXIMUM_SIGN_LETTERS = 15; public static final short MAXIMUM_SIGN_LETTERS = 15;
// 15 dashes fit on one sign line with the default resource pack:
public static final int MAXIMUM_SIGN_WIDTH = (short) getMinecraftStringWidth("---------------");
private static final SimpleCache<String, Material> MATERIAL_CACHE = new SimpleCache<>(Properties.CACHE_SIZE); private static final SimpleCache<String, Material> MATERIAL_CACHE = new SimpleCache<>(Properties.CACHE_SIZE);
@ -155,17 +164,17 @@ public class MaterialUtil {
* @return ItemStack's name * @return ItemStack's name
*/ */
public static String getSignName(ItemStack itemStack) { public static String getSignName(ItemStack itemStack) {
return getName(itemStack, MAXIMUM_SIGN_LETTERS); return getName(itemStack, MAXIMUM_SIGN_WIDTH);
} }
/** /**
* Returns item's name, with a maximum length * Returns item's name, with a maximum width
* *
* @param itemStack ItemStack to name * @param itemStack ItemStack to name
* @param maxLength The max length that the name should have; 0 or below if it should be unlimited * @param maxWidth The max width that the name should have; 0 or below if it should be unlimited
* @return ItemStack's name * @return ItemStack's name
*/ */
public static String getName(ItemStack itemStack, int maxLength) { public static String getName(ItemStack itemStack, int maxWidth) {
String alias = Odd.getAlias(itemStack); String alias = Odd.getAlias(itemStack);
String itemName = alias != null ? alias : itemStack.getType().toString(); String itemName = alias != null ? alias : itemStack.getType().toString();
@ -179,18 +188,18 @@ public class MaterialUtil {
metaData = "#" + Metadata.getItemCode(itemStack); metaData = "#" + Metadata.getItemCode(itemStack);
} }
int codeLength = (itemName + durability + metaData).length(); int codeWidth = getMinecraftStringWidth(itemName + durability + metaData);
String code = itemName; String code = itemName;
if (maxLength > 0 && codeLength > maxLength) { if (maxWidth > 0 && codeWidth > maxWidth) {
int exceeding = codeLength - maxLength; int exceeding = codeWidth - maxWidth;
code = getShortenedName(code, code.length() - exceeding); code = getShortenedName(code, getMinecraftStringWidth(code) - exceeding);
} }
code = StringUtil.capitalizeFirstLetter(code, '_') + durability + metaData; code = StringUtil.capitalizeFirstLetter(code, '_') + durability + metaData;
ItemStack codeItem = getItem(code); ItemStack codeItem = getItem(code);
if (!equals(itemStack, codeItem)) { if (!equals(itemStack, codeItem)) {
throw new IllegalArgumentException("Cannot generate code for item " + itemStack + " with maximum length of " + maxLength throw new IllegalArgumentException("Cannot generate code for item " + itemStack + " with maximum length of " + maxWidth
+ " (code " + code + " results in item " + codeItem + ")"); + " (code " + code + " results in item " + codeItem + ")");
} }
@ -201,44 +210,54 @@ public class MaterialUtil {
* Get an item name shortened to a max length that is still reversable by {@link #getMaterial(String)} * Get an item name shortened to a max length that is still reversable by {@link #getMaterial(String)}
* *
* @param itemName The name of the item * @param itemName The name of the item
* @param maxLength The max length * @param maxWidth The max width
* @return The name shortened to the max length * @return The name shortened to the max length
*/ */
public static String getShortenedName(String itemName, int maxLength) { public static String getShortenedName(String itemName, int maxWidth) {
if (itemName.length() <= maxLength) { int width = getMinecraftStringWidth(itemName);
if (width <= maxWidth) {
return itemName; return itemName;
} }
int exceeding = itemName.length() - maxLength; int exceeding = width - maxWidth;
String[] itemParts = itemName.split("_"); String[] itemParts = itemName.split("_");
int shortestIndex = 0; int shortestIndex = 0;
int longestIndex = 0; int longestIndex = 0;
for (int i = 0; i < itemParts.length; i++) { for (int i = 0; i < itemParts.length; i++) {
if (itemParts[longestIndex].length() < itemParts[i].length()) { if (getMinecraftStringWidth(itemParts[longestIndex]) < getMinecraftStringWidth(itemParts[i])) {
longestIndex = i; longestIndex = i;
} }
if (itemParts[shortestIndex].length() > itemParts[i].length()) { if (getMinecraftStringWidth(itemParts[shortestIndex]) > getMinecraftStringWidth(itemParts[i])) {
shortestIndex = i; shortestIndex = i;
} }
} }
for (int i = itemParts.length - 1; i >= 0 && exceeding > 0; i--) { for (int i = itemParts.length - 1; i >= 0 && exceeding > 0; i--) {
int remove = 0; int remove = 0;
if (itemParts[i].length() > itemParts[shortestIndex].length()) { int partWidth = getMinecraftStringWidth(itemParts[i]);
remove = itemParts[i].length() - itemParts[shortestIndex].length(); int shortestWidth = getMinecraftStringWidth(itemParts[shortestIndex]);
if (partWidth > shortestWidth) {
remove = partWidth - shortestWidth;
} }
if (remove > exceeding) { if (remove > exceeding) {
remove = exceeding; remove = exceeding;
} }
itemParts[i] = itemParts[i].substring(0, itemParts[i].length() - remove);
exceeding -= remove; while (remove > 0) {
} int endWidth = getMinecraftCharWidth(itemParts[i].charAt(itemParts[i].length() - 1));
while (exceeding > 0) {
for (int i = itemParts.length - 1; i >= 0 && exceeding > 0; i--) {
itemParts[i] = itemParts[i].substring(0, itemParts[i].length() - 1); itemParts[i] = itemParts[i].substring(0, itemParts[i].length() - 1);
exceeding--; remove -= endWidth;
exceeding -= endWidth;
} }
} }
while (exceeding > 0) {
for (int i = itemParts.length - 1; i >= 0 && exceeding > 0; i--) {
int endWidth = getMinecraftCharWidth(itemParts[i].charAt(itemParts[i].length() - 1));
itemParts[i] = itemParts[i].substring(0, itemParts[i].length() - 1);
exceeding -= endWidth;
}
}
return String.join("_", itemParts); return String.join("_", itemParts);
} }

View File

@ -77,4 +77,39 @@ public class StringUtil {
return output; return output;
} }
private static String characters = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'abcdefghijklmnopqrstuvwxyz{|}~¦ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»";
private static int[] extraWidth = {4,2,5,6,6,6,6,3,5,5,5,6,2,6,2,6,6,6,6,6,6,6,6,6,6,6,2,2,5,6,5,6,7,6,6,6,6,6,6,6,6,4,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,4,6,4,6,6,3,6,6,6,6,6,5,6,6,2,6,5,3,6,6,6,6,6,6,6,4,6,6,6,6,6,6,5,2,5,7,6,6,6,6,6,6,6,6,6,6,6,6,4,6,3,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,4,6,6,3,6,6,6,6,6,6,6,7,6,6,6,2,6,6,8,9,9,6,6,6,8,8,6,8,8,8,8,8,6,6,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,6,9,9,9,5,9,9,8,7,7,8,7,8,8,8,7,8,8,7,9,9,6,7,7,7,7,7,9,6,7,8,7,6,6,9,7,6,7,1};
/**
* Get the width that a character is displayed with in the default resource pack.
* This relies on a hardcoded character to width mapping and might not be precise in places.
* @param c The character to get the width of
* @return The width of the character (will return 10 for characters that we don't know the width of)
*/
public static int getMinecraftCharWidth(char c) {
if (c != ChatColor.COLOR_CHAR) {
int index = characters.indexOf(c);
if (index > -1) {
return extraWidth[index];
} else {
return 10;
}
}
return 0;
}
/**
* Get the width that a string is displayed with in the default resource pack.
* This relies on a hardcoded character to width mapping and might not be precise in places.
* @param string The string to get the width of
* @return The width of the string
*/
public static int getMinecraftStringWidth(String string) {
int width = 0;
for (char c : string.toCharArray()) {
width += getMinecraftCharWidth(c);
}
return width;
}
} }

View File

@ -67,7 +67,7 @@ public class Messages {
@PrecededBySpace @PrecededBySpace
public static String PLAYER_NOT_FOUND = "Player not found!"; public static String PLAYER_NOT_FOUND = "Player not found!";
public static String NO_PERMISSION = "You don't have permissions to do that!"; public static String NO_PERMISSION = "You don't have permissions to do that!";
public static String INCORRECT_ITEM_ID = "You have specified invalid item id!"; public static String INCORRECT_ITEM_ID = "You have specified an invalid item id!";
public static String NOT_ENOUGH_PROTECTIONS = "Could not create a protection!"; public static String NOT_ENOUGH_PROTECTIONS = "Could not create a protection!";
@PrecededBySpace @PrecededBySpace

View File

@ -1,6 +1,7 @@
package com.Acrobot.ChestShop.Listeners.PreShopCreation; package com.Acrobot.ChestShop.Listeners.PreShopCreation;
import com.Acrobot.Breeze.Utils.MaterialUtil; import com.Acrobot.Breeze.Utils.MaterialUtil;
import com.Acrobot.Breeze.Utils.StringUtil;
import com.Acrobot.ChestShop.Configuration.Messages; import com.Acrobot.ChestShop.Configuration.Messages;
import com.Acrobot.ChestShop.Configuration.Properties; import com.Acrobot.ChestShop.Configuration.Properties;
import com.Acrobot.ChestShop.Events.PreShopCreationEvent; import com.Acrobot.ChestShop.Events.PreShopCreationEvent;
@ -33,22 +34,17 @@ public class ItemChecker implements Listener {
if (item == null) { if (item == null) {
if (Properties.ALLOW_AUTO_ITEM_FILL && itemCode.equals(AUTOFILL_CODE)) { if (Properties.ALLOW_AUTO_ITEM_FILL && itemCode.equals(AUTOFILL_CODE)) {
boolean foundItem = false;
Chest chest = uBlock.findConnectedChest(event.getSign()); Chest chest = uBlock.findConnectedChest(event.getSign());
if (chest != null) { if (chest != null) {
for (ItemStack stack : chest.getInventory().getContents()) { for (ItemStack stack : chest.getInventory().getContents()) {
if (!MaterialUtil.isEmpty(stack)) { if (!MaterialUtil.isEmpty(stack)) {
itemCode = MaterialUtil.getSignName(stack); item = stack;
event.setSignLine(ITEM_LINE, itemCode);
foundItem = true;
break; break;
} }
} }
} }
if (!foundItem) { if (item == null) {
event.setSignLine(ITEM_LINE, ChatColor.BOLD + ChestShopSign.AUTOFILL_CODE); event.setSignLine(ITEM_LINE, ChatColor.BOLD + ChestShopSign.AUTOFILL_CODE);
event.setOutcome(ITEM_AUTOFILL); event.setOutcome(ITEM_AUTOFILL);
event.getPlayer().sendMessage(Messages.prefix(Messages.CLICK_TO_AUTOFILL_ITEM)); event.getPlayer().sendMessage(Messages.prefix(Messages.CLICK_TO_AUTOFILL_ITEM));
@ -60,10 +56,14 @@ public class ItemChecker implements Listener {
} }
} }
if (itemCode.length() > MAXIMUM_SIGN_LETTERS) { itemCode = MaterialUtil.getSignName(item);
if (StringUtil.getMinecraftStringWidth(itemCode) > MAXIMUM_SIGN_WIDTH) {
event.setOutcome(INVALID_ITEM); event.setOutcome(INVALID_ITEM);
return; return;
} }
event.setSignLine(ITEM_LINE, itemCode);
} }
private static boolean isSameItem(String newCode, ItemStack item) { private static boolean isSameItem(String newCode, ItemStack item) {

View File

@ -29,10 +29,11 @@ public class MaterialTest {
@Test @Test
public void testCodes() { public void testCodes() {
for (Material material : Material.values()) { for (Material material : Material.values()) {
if (!material.isLegacy()) { if (material.isLegacy()) {
String shortenedName = MaterialUtil.getShortenedName(material.toString(), MaterialUtil.MAXIMUM_SIGN_LETTERS); continue;
assertSame(shortenedName + " does not produce " + material, material, MaterialUtil.getMaterial(shortenedName));
} }
String shortenedName = MaterialUtil.getShortenedName(material.toString(), MaterialUtil.MAXIMUM_SIGN_WIDTH);
assertSame(material, MaterialUtil.getMaterial(shortenedName));
} }
} }
} }