2012-06-08 15:28:36 +02:00
package com.Acrobot.Breeze.Utils ;
2018-03-12 21:01:28 +01:00
import com.Acrobot.Breeze.Collection.SimpleCache ;
2013-01-24 22:35:28 +01:00
import com.Acrobot.ChestShop.ChestShop ;
2018-03-12 21:01:28 +01:00
import com.Acrobot.ChestShop.Configuration.Properties ;
2018-01-06 17:44:35 +01:00
import com.google.common.collect.ImmutableMap ;
import de.themoep.ShowItem.api.ShowItem ;
2013-07-30 17:27:04 +02:00
import info.somethingodd.OddItem.OddItem ;
2012-06-08 15:28:36 +02:00
import org.bukkit.CoalType ;
import org.bukkit.DyeColor ;
import org.bukkit.Material ;
import org.bukkit.TreeSpecies ;
import org.bukkit.entity.EntityType ;
2018-01-06 17:44:35 +01:00
import org.bukkit.entity.Player ;
2012-06-08 15:28:36 +02:00
import org.bukkit.inventory.ItemStack ;
2017-05-04 19:54:49 +02:00
import org.bukkit.inventory.meta.BookMeta ;
2013-01-24 22:35:28 +01:00
import org.bukkit.inventory.meta.ItemMeta ;
2012-06-08 15:28:36 +02:00
import org.bukkit.material.* ;
2018-01-06 17:44:35 +01:00
import org.bukkit.plugin.Plugin ;
import org.json.simple.JSONObject ;
2012-06-08 15:28:36 +02:00
2018-01-06 17:44:35 +01:00
import java.util.ArrayList ;
import java.util.Arrays ;
2017-11-15 21:08:32 +01:00
import java.util.Collection ;
2018-03-14 18:53:34 +01:00
import java.util.HashMap ;
2018-01-06 17:44:35 +01:00
import java.util.List ;
2018-03-14 18:53:34 +01:00
import java.util.Map ;
2018-01-06 17:44:35 +01:00
import java.util.logging.Level ;
2012-06-08 15:28:36 +02:00
import java.util.regex.Matcher ;
import java.util.regex.Pattern ;
2018-01-06 17:44:35 +01:00
import java.util.stream.Collectors ;
2012-06-08 15:28:36 +02:00
/ * *
* @author Acrobot
* /
public class MaterialUtil {
2012-10-21 22:45:30 +02:00
public static final Pattern DURABILITY = Pattern . compile ( " :( \\ d)* " ) ;
2013-01-24 22:35:28 +01:00
public static final Pattern METADATA = Pattern . compile ( " #([0-9a-zA-Z])* " ) ;
2012-06-08 15:28:36 +02:00
2013-01-15 21:33:00 +01:00
public static final boolean LONG_NAME = true ;
public static final boolean SHORT_NAME = false ;
2018-03-12 21:01:28 +01:00
public static final short MAXIMUM_SIGN_LETTERS = 15 ;
private static final SimpleCache < String , Material > MATERIAL_CACHE = new SimpleCache < > ( Properties . CACHE_SIZE ) ;
2013-01-15 21:33:00 +01:00
2012-06-08 15:28:36 +02:00
/ * *
* Checks if the itemStack is empty or null
*
* @param item Item to check
* @return Is the itemStack empty ?
* /
public static boolean isEmpty ( ItemStack item ) {
return item = = null | | item . getType ( ) = = Material . AIR ;
}
/ * *
* Checks if the itemStacks are equal , ignoring their amount
*
* @param one first itemStack
* @param two second itemStack
* @return Are they equal ?
* /
public static boolean equals ( ItemStack one , ItemStack two ) {
2017-05-04 19:54:49 +02:00
if ( one = = null | | two = = null ) {
2018-01-08 23:56:58 +01:00
return one = = two ;
2017-05-04 19:54:49 +02:00
}
if ( one . isSimilar ( two ) ) {
return true ;
}
2018-03-14 18:53:34 +01:00
// Special check for banners as they might include the deprecated base color
if ( one . getType ( ) = = two . getType ( )
& & one . getType ( ) = = Material . BANNER
& & one . getDurability ( ) = = two . getDurability ( ) ) {
Map < String , Object > m1 = new HashMap < > ( one . getItemMeta ( ) . serialize ( ) ) ;
Map < String , Object > m2 = new HashMap < > ( two . getItemMeta ( ) . serialize ( ) ) ;
Object c1 = m1 . remove ( " base-color " ) ;
Object c2 = m2 . remove ( " base-color " ) ;
return ( one . getData ( ) . equals ( two . getData ( ) ) | | c1 . equals ( c2 ) ) & & m1 . equals ( m2 ) ;
}
2017-05-04 19:54:49 +02:00
// Special check for books as their pages might change when serialising (See SPIGOT-3206)
return one . getType ( ) = = two . getType ( )
& & one . getDurability ( ) = = two . getDurability ( )
& & one . getData ( ) . equals ( two . getData ( ) )
& & one . hasItemMeta ( ) & & two . hasItemMeta ( )
& & one . getItemMeta ( ) instanceof BookMeta & & two . getItemMeta ( ) instanceof BookMeta
& & one . getItemMeta ( ) . serialize ( ) . equals ( two . getItemMeta ( ) . serialize ( ) ) ;
2012-06-08 15:28:36 +02:00
}
/ * *
* Gives you a Material from a String ( doesn ' t have to be fully typed in )
*
* @param name Name of the material
* @return Material found
* /
public static Material getMaterial ( String name ) {
2018-03-12 21:01:28 +01:00
String formatted = name . toUpperCase ( ) ;
2012-06-08 15:28:36 +02:00
2018-03-12 21:01:28 +01:00
Material material = MATERIAL_CACHE . get ( formatted ) ;
if ( material ! = null ) {
return material ;
2013-02-11 01:09:12 +01:00
}
2013-02-11 17:09:34 +01:00
2018-03-12 21:01:28 +01:00
material = Material . matchMaterial ( name ) ;
2013-02-11 17:09:34 +01:00
2012-06-08 15:28:36 +02:00
if ( material ! = null ) {
2013-02-11 17:09:34 +01:00
MATERIAL_CACHE . put ( formatted , material ) ;
2012-06-08 15:28:36 +02:00
return material ;
}
2018-03-12 21:01:28 +01:00
2018-03-14 15:07:13 +01:00
String [ ] nameParts = name . toUpperCase ( ) . split ( " |_ " ) ;
2012-06-08 15:28:36 +02:00
short length = Short . MAX_VALUE ;
for ( Material currentMaterial : Material . values ( ) ) {
2018-03-12 21:01:28 +01:00
String matName = currentMaterial . toString ( ) ;
2012-06-08 15:28:36 +02:00
2018-03-12 21:01:28 +01:00
if ( matName . length ( ) < length & & matName . startsWith ( formatted ) ) {
2012-06-08 15:28:36 +02:00
length = ( short ) matName . length ( ) ;
material = currentMaterial ;
2018-03-12 21:01:28 +01:00
} 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 ;
}
}
2012-06-08 15:28:36 +02:00
}
}
2013-02-11 17:09:34 +01:00
MATERIAL_CACHE . put ( formatted , material ) ;
2012-06-08 15:28:36 +02:00
return material ;
}
/ * *
* Returns item ' s name
*
* @param itemStack ItemStack to name
* @return ItemStack ' s name
* /
public static String getName ( ItemStack itemStack ) {
2018-03-12 21:01:28 +01:00
return getName ( itemStack , 0 ) ;
2012-06-08 15:28:36 +02:00
}
/ * *
* Returns item ' s name
*
* @param itemStack ItemStack to name
* @param showDataValue Should we also show the data value ?
* @return ItemStack ' s name
2018-03-12 21:01:28 +01:00
* @deprecated Use { @link # getName ( ItemStack , int ) }
2012-06-08 15:28:36 +02:00
* /
2018-03-12 21:01:28 +01:00
@Deprecated
2012-06-08 15:28:36 +02:00
public static String getName ( ItemStack itemStack , boolean showDataValue ) {
String dataName = DataValue . name ( itemStack ) ;
if ( dataName ! = null & & showDataValue ) {
return StringUtil . capitalizeFirstLetter ( dataName + '_' + itemStack . getType ( ) , '_' ) ;
} else {
return StringUtil . capitalizeFirstLetter ( itemStack . getType ( ) . toString ( ) , '_' ) ;
}
}
/ * *
* Returns item ' s name , just like on the sign
*
* @param itemStack ItemStack to name
* @return ItemStack ' s name
* /
public static String getSignName ( ItemStack itemStack ) {
2018-03-12 21:01:28 +01:00
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 ) {
2017-11-15 21:08:32 +01:00
String alias = Odd . getAlias ( itemStack ) ;
2018-03-12 21:01:28 +01:00
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 ( ) ;
}
2012-06-08 15:28:36 +02:00
}
2018-03-12 21:01:28 +01:00
data = data ! = null ? data + " _ " : " " ;
2012-06-08 15:28:36 +02:00
2018-03-12 21:01:28 +01:00
String metaData = " " ;
2013-02-07 14:16:50 +01:00
if ( itemStack . hasItemMeta ( ) ) {
2018-03-12 21:01:28 +01:00
metaData = " # " + Metadata . getItemCode ( itemStack ) ;
}
2018-03-16 18:24:52 +01:00
int codeLength = ( data + itemName + durability + metaData ) . length ( ) ;
String code = data + itemName ;
if ( maxLength > 0 & & codeLength > maxLength ) {
int exceeding = codeLength - maxLength ;
code = getShortenedName ( code , code . length ( ) - exceeding ) ;
2018-03-12 21:01:28 +01:00
}
2018-03-16 18:24:52 +01:00
code = StringUtil . capitalizeFirstLetter ( code , '_' ) + durability + metaData ;
2018-03-12 21:01:28 +01:00
ItemStack codeItem = getItem ( code ) ;
if ( ! equals ( itemStack , codeItem ) ) {
2018-03-16 18:24:52 +01:00
throw new IllegalArgumentException ( " Cannot generate code for item " + itemStack + " with maximum length of " + maxLength
+ " (code " + code + " results in item " + codeItem + " ) " ) ;
2012-06-08 15:28:36 +02:00
}
2018-03-12 21:01:28 +01:00
return code ;
2012-06-08 15:28:36 +02:00
}
2018-03-14 15:07:13 +01:00
/ * *
* 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
* @return The name shortened to the max length
* /
public static String getShortenedName ( String itemName , int maxLength ) {
if ( itemName . length ( ) < = maxLength ) {
return itemName ;
}
int exceeding = itemName . length ( ) - maxLength ;
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 ( ) ) {
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 - - ;
}
}
}
return String . join ( " _ " , itemParts ) ;
}
2012-06-08 15:28:36 +02:00
/ * *
* Gives you an ItemStack from a String
*
* @param itemName Item name
* @return ItemStack
* /
public static ItemStack getItem ( String itemName ) {
ItemStack itemStack = Odd . getFromString ( itemName ) ;
if ( itemStack ! = null ) {
return itemStack ;
}
2017-09-23 16:19:00 +02:00
String [ ] split = itemName . split ( " [: \\ -#] " ) ;
for ( int i = 0 ; i < split . length ; i + + ) {
split [ i ] = split [ i ] . trim ( ) ;
}
2012-06-08 15:28:36 +02:00
Material material = getMaterial ( split [ 0 ] ) ;
2013-02-08 19:29:13 +01:00
short durability = getDurability ( itemName ) ;
2018-03-14 18:53:34 +01:00
byte data = - 1 ;
2012-06-08 15:28:36 +02:00
if ( material = = null ) {
2012-11-23 21:01:43 +01:00
if ( ! split [ 0 ] . contains ( " " ) ) {
2012-06-08 15:28:36 +02:00
return null ;
}
2018-03-14 15:08:51 +01:00
for ( int index = split [ 0 ] . indexOf ( ' ' ) ; index > = 0 & & index + 1 < split [ 0 ] . length ( ) ; index = split [ 0 ] . indexOf ( ' ' , index + 1 ) ) {
material = getMaterial ( split [ 0 ] . substring ( index + 1 ) ) ;
2012-11-23 21:01:43 +01:00
2013-02-08 19:29:13 +01:00
if ( material ! = null ) {
if ( durability = = 0 ) {
2018-03-14 18:53:34 +01:00
durability = data = DataValue . get ( split [ 0 ] . substring ( 0 , index ) , material ) ;
2013-02-08 19:29:13 +01:00
}
2012-06-08 15:28:36 +02:00
2013-02-08 19:29:13 +01:00
break ;
}
2012-06-08 15:28:36 +02:00
}
2013-02-08 19:29:13 +01:00
if ( material = = null ) {
return null ;
2012-06-08 15:28:36 +02:00
}
}
2013-02-08 19:29:13 +01:00
itemStack = new ItemStack ( material ) ;
2012-06-08 15:28:36 +02:00
itemStack . setDurability ( durability ) ;
2018-03-14 18:53:34 +01:00
if ( data > - 1 ) {
itemStack . getData ( ) . setData ( data ) ;
}
2012-06-08 15:28:36 +02:00
2013-01-24 22:35:28 +01:00
ItemMeta meta = getMetadata ( itemName ) ;
if ( meta ! = null ) {
itemStack . setItemMeta ( meta ) ;
}
2013-02-11 17:09:34 +01:00
2012-06-08 15:28:36 +02:00
return itemStack ;
}
/ * *
* Returns the durability from a string
*
* @param itemName Item name
* @return Durability found
* /
public static short getDurability ( String itemName ) {
Matcher m = DURABILITY . matcher ( itemName ) ;
if ( ! m . find ( ) ) {
return 0 ;
}
String data = m . group ( ) ;
if ( data = = null | | data . isEmpty ( ) ) {
return 0 ;
}
data = data . substring ( 1 ) ;
2012-10-21 22:45:30 +02:00
return NumberUtil . isShort ( data ) ? Short . valueOf ( data ) : 0 ;
2012-06-08 15:28:36 +02:00
}
2013-01-24 22:35:28 +01:00
/ * *
* Returns metadata from a string
*
* @param itemName Item name
* @return Metadata found
* /
public static ItemMeta getMetadata ( String itemName ) {
Matcher m = METADATA . matcher ( itemName ) ;
if ( ! m . find ( ) ) {
return null ;
}
String group = m . group ( ) . substring ( 1 ) ;
return Metadata . getFromCode ( group ) ;
}
2018-01-12 17:54:57 +01:00
//1.13 TODO: Get rid of numeric data values with the API that replaces MaterialData
2012-06-08 15:28:36 +02:00
public static class DataValue {
/ * *
* Gets the data value from a string
*
* @param type Data Value string
* @param material Material
* @return data value
* /
public static byte get ( String type , Material material ) {
if ( material = = null | | material . getData ( ) = = null ) {
return 0 ;
}
type = type . toUpperCase ( ) . replace ( " " , " _ " ) ;
MaterialData materialData = material . getNewData ( ( byte ) 0 ) ;
if ( materialData instanceof TexturedMaterial ) {
TexturedMaterial texturedMaterial = ( TexturedMaterial ) materialData ;
for ( Material mat : texturedMaterial . getTextures ( ) ) {
if ( mat . name ( ) . startsWith ( type ) & & ! mat . equals ( material ) ) {
return ( byte ) texturedMaterial . getTextures ( ) . indexOf ( mat ) ;
}
}
2018-03-14 18:53:34 +01:00
} else if ( materialData instanceof Colorable | | material = = Material . BANNER ) { // Banners might not use the Banner MaterialData...
2012-06-08 15:28:36 +02:00
DyeColor color ;
try {
color = DyeColor . valueOf ( type ) ;
} catch ( IllegalArgumentException exception ) {
return 0 ;
}
2018-03-14 18:53:34 +01:00
if ( material = = Material . INK_SACK | | material = = Material . BANNER ) {
2013-02-07 14:16:50 +01:00
return color . getDyeData ( ) ;
2012-06-08 15:28:36 +02:00
}
2013-02-07 14:16:50 +01:00
return color . getWoolData ( ) ;
2012-06-08 15:28:36 +02:00
} else if ( materialData instanceof Tree ) {
try {
return TreeSpecies . valueOf ( type ) . getData ( ) ;
} catch ( IllegalArgumentException ex ) {
return 0 ;
}
} else if ( materialData instanceof SpawnEgg ) {
try {
EntityType entityType = EntityType . valueOf ( type ) ;
return ( byte ) entityType . getTypeId ( ) ;
} catch ( IllegalArgumentException ex ) {
return 0 ;
}
} else if ( materialData instanceof Coal ) {
try {
return CoalType . valueOf ( type ) . getData ( ) ;
} catch ( IllegalArgumentException ex ) {
return 0 ;
}
}
return 0 ;
}
/ * *
* Returns a string with the DataValue
*
* @param itemStack ItemStack to describe
* @return Data value string
* /
public static String name ( ItemStack itemStack ) {
MaterialData data = itemStack . getData ( ) ;
if ( data = = null ) {
return null ;
}
2018-03-14 18:53:34 +01:00
// Banner do not return the Banner MaterialData? Wat?!?
if ( data . getItemType ( ) = = Material . BANNER & & data . getData ( ) < 16 ) {
return DyeColor . getByDyeData ( data . getData ( ) ) . name ( ) ;
}
2012-06-08 15:28:36 +02:00
if ( data instanceof TexturedMaterial ) {
return ( ( TexturedMaterial ) data ) . getMaterial ( ) . name ( ) ;
} else if ( data instanceof Colorable ) {
2012-11-28 21:30:53 +01:00
DyeColor color = ( ( Colorable ) data ) . getColor ( ) ;
return ( color ! = null ? color . name ( ) : null ) ;
2012-06-08 15:28:36 +02:00
} else if ( data instanceof Tree ) {
//TreeSpecies specie = TreeSpecies.getByData((byte) (data.getData() & 3)); //This works, but not as intended
TreeSpecies specie = ( ( Tree ) data ) . getSpecies ( ) ;
return ( specie ! = null & & specie ! = TreeSpecies . GENERIC ? specie . name ( ) : null ) ;
} else if ( data instanceof SpawnEgg ) {
EntityType type = ( ( SpawnEgg ) data ) . getSpawnedType ( ) ;
return ( type ! = null ? type . name ( ) : null ) ;
} else if ( data instanceof Coal ) {
CoalType coal = ( ( Coal ) data ) . getType ( ) ;
return ( coal ! = null & & coal ! = CoalType . COAL ? coal . name ( ) : null ) ;
} else {
return null ;
}
}
}
2013-01-24 22:35:28 +01:00
public static class Metadata {
/ * *
2018-03-12 21:01:28 +01:00
* Returns the ItemMeta represented by this code
2013-01-24 22:35:28 +01:00
*
2018-03-12 21:01:28 +01:00
* @param code Code representing the ItemMeta
* @return ItemMeta represented by code
2013-01-24 22:35:28 +01:00
* /
public static ItemMeta getFromCode ( String code ) {
ItemStack item = ChestShop . getItemDatabase ( ) . getFromCode ( code ) ;
if ( item = = null ) {
return null ;
} else {
return item . getItemMeta ( ) ;
}
}
/ * *
* Returns the code for this item
*
* @param item Item being represented
* @return Code representing the item
* /
public static String getItemCode ( ItemStack item ) {
return ChestShop . getItemDatabase ( ) . getItemCode ( item ) ;
}
}
2012-06-08 15:28:36 +02:00
public static class Odd {
private static boolean isInitialized = false ;
/ * *
* Returns the item stack from OddItem plugin
*
* @param itemName Item name to parse
* @return itemStack that was parsed
* /
public static ItemStack getFromString ( String itemName ) {
if ( ! isInitialized ) {
return null ;
}
String name = itemName . replace ( ':' , ';' ) ;
try {
return OddItem . getItemStack ( name ) ;
} catch ( Exception ex ) {
return null ;
}
}
2017-11-15 21:08:32 +01:00
public static String getAlias ( ItemStack itemStack ) {
if ( ! isInitialized ) {
return null ;
}
try {
Collection < String > aliases = OddItem . getAliases ( itemStack ) ;
if ( ! aliases . isEmpty ( ) ) {
return aliases . iterator ( ) . next ( ) ;
}
} catch ( Exception ignored ) { }
return null ;
}
2012-06-08 15:28:36 +02:00
/ * *
* Lets the class know that it ' s safe to use the OddItem methods now
* /
public static void initialize ( ) {
isInitialized = true ;
}
}
2018-01-06 17:44:35 +01:00
public static class Show {
private static ShowItem showItem = null ;
/ * *
* Lets the class know that it ' s safe to use the ShowItem methods now
*
* @param plugin
* /
public static void initialize ( Plugin plugin ) {
showItem = ( ShowItem ) plugin ;
}
/ * *
* Send a message with hover info and icons
*
* @param player The player to send the message to
* @param message The raw message
* @param stock The items in stock
* /
public static boolean sendMessage ( Player player , String message , ItemStack [ ] stock ) {
if ( showItem = = null ) {
return false ;
}
List < String > itemJson = new ArrayList < > ( ) ;
2018-01-08 22:53:44 +01:00
for ( ItemStack item : InventoryUtil . mergeSimilarStacks ( stock ) ) {
2018-01-06 17:44:35 +01:00
try {
itemJson . add ( showItem . getItemConverter ( ) . createComponent ( item , Level . OFF ) . toJsonString ( player ) ) ;
} catch ( Exception e ) {
ChestShop . getPlugin ( ) . getLogger ( ) . log ( Level . WARNING , " Error while trying to send message ' " + message + " ' to player " + player . getName ( ) + " : " + e . getMessage ( ) ) ;
return false ;
}
}
String joinedItemJson = itemJson . stream ( ) . collect ( Collectors . joining ( " , " + new JSONObject ( ImmutableMap . of ( " text " , " " ) ) . toJSONString ( ) + " , " ) ) ;
String messageJsonString = Arrays . stream ( message . split ( " %item " ) )
. map ( s - > new JSONObject ( ImmutableMap . of ( " text " , s ) ) . toJSONString ( ) )
. collect ( Collectors . joining ( " , " + joinedItemJson + " , " ) ) ;
while ( messageJsonString . startsWith ( " , " ) ) {
messageJsonString = messageJsonString . substring ( 1 ) ;
}
while ( messageJsonString . endsWith ( " , " ) ) {
messageJsonString = messageJsonString . substring ( 0 , messageJsonString . length ( ) - 1 ) ;
}
showItem . tellRaw ( player , messageJsonString ) ;
return true ;
}
}
2012-06-08 15:28:36 +02:00
}