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.stream.Collectors;
import static com.Acrobot.Breeze.Utils.StringUtil.getMinecraftCharWidth;
import static com.Acrobot.Breeze.Utils.StringUtil.getMinecraftStringWidth;
/**
* @author Acrobot
*/
@ -40,7 +43,13 @@ public class MaterialUtil {
public static final boolean LONG_NAME = true;
public static final boolean SHORT_NAME = false;
/**
* @deprecated Use {@link MaterialUtil#MAXIMUM_SIGN_WIDTH}
*/
@Deprecated
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);
@ -155,17 +164,17 @@ public class MaterialUtil {
* @return ItemStack's name
*/
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 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
*/
public static String getName(ItemStack itemStack, int maxLength) {
public static String getName(ItemStack itemStack, int maxWidth) {
String alias = Odd.getAlias(itemStack);
String itemName = alias != null ? alias : itemStack.getType().toString();
@ -179,18 +188,18 @@ public class MaterialUtil {
metaData = "#" + Metadata.getItemCode(itemStack);
}
int codeLength = (itemName + durability + metaData).length();
int codeWidth = getMinecraftStringWidth(itemName + durability + metaData);
String code = itemName;
if (maxLength > 0 && codeLength > maxLength) {
int exceeding = codeLength - maxLength;
code = getShortenedName(code, code.length() - exceeding);
if (maxWidth > 0 && codeWidth > maxWidth) {
int exceeding = codeWidth - maxWidth;
code = getShortenedName(code, getMinecraftStringWidth(code) - exceeding);
}
code = StringUtil.capitalizeFirstLetter(code, '_') + durability + metaData;
ItemStack codeItem = getItem(code);
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 + ")");
}
@ -201,44 +210,54 @@ public class MaterialUtil {
* 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 maxLength The max length
* @param maxWidth The max width
* @return The name shortened to the max length
*/
public static String getShortenedName(String itemName, int maxLength) {
if (itemName.length() <= maxLength) {
public static String getShortenedName(String itemName, int maxWidth) {
int width = getMinecraftStringWidth(itemName);
if (width <= maxWidth) {
return itemName;
}
int exceeding = itemName.length() - maxLength;
int exceeding = width - maxWidth;
String[] itemParts = itemName.split("_");
int shortestIndex = 0;
int longestIndex = 0;
for (int i = 0; i < itemParts.length; i++) {
if (itemParts[longestIndex].length() < itemParts[i].length()) {
if (getMinecraftStringWidth(itemParts[longestIndex]) < getMinecraftStringWidth(itemParts[i])) {
longestIndex = i;
}
if (itemParts[shortestIndex].length() > itemParts[i].length()) {
if (getMinecraftStringWidth(itemParts[shortestIndex]) > getMinecraftStringWidth(itemParts[i])) {
shortestIndex = i;
}
}
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();
int partWidth = getMinecraftStringWidth(itemParts[i]);
int shortestWidth = getMinecraftStringWidth(itemParts[shortestIndex]);
if (partWidth > shortestWidth) {
remove = partWidth - shortestWidth;
}
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--) {
while (remove > 0) {
int endWidth = getMinecraftCharWidth(itemParts[i].charAt(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);
}

View File

@ -77,4 +77,39 @@ public class StringUtil {
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
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 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!";
@PrecededBySpace

View File

@ -1,6 +1,7 @@
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;
@ -33,22 +34,17 @@ public class ItemChecker implements Listener {
if (item == null) {
if (Properties.ALLOW_AUTO_ITEM_FILL && itemCode.equals(AUTOFILL_CODE)) {
boolean foundItem = false;
Chest chest = uBlock.findConnectedChest(event.getSign());
if (chest != null) {
for (ItemStack stack : chest.getInventory().getContents()) {
if (!MaterialUtil.isEmpty(stack)) {
itemCode = MaterialUtil.getSignName(stack);
event.setSignLine(ITEM_LINE, itemCode);
foundItem = true;
item = stack;
break;
}
}
}
if (!foundItem) {
if (item == null) {
event.setSignLine(ITEM_LINE, ChatColor.BOLD + ChestShopSign.AUTOFILL_CODE);
event.setOutcome(ITEM_AUTOFILL);
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);
return;
}
event.setSignLine(ITEM_LINE, itemCode);
}
private static boolean isSameItem(String newCode, ItemStack item) {

View File

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