diff --git a/platform/platform-bukkit/src/main/java/taboolib/library/xseries/NoteBlockMusic.java b/platform/platform-bukkit/src/main/java/taboolib/library/xseries/NoteBlockMusic.java
index 2eda62302..948c39b04 100644
--- a/platform/platform-bukkit/src/main/java/taboolib/library/xseries/NoteBlockMusic.java
+++ b/platform/platform-bukkit/src/main/java/taboolib/library/xseries/NoteBlockMusic.java
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
- * Copyright (c) 2022 Crypto Morin
+ * Copyright (c) 2023 Crypto Morin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -41,7 +41,7 @@
/**
* NoteBlockMusic - Write music scripts for Minecraft.
- * You can write small text scripts for Minecraft note blocks
+ * You can write small text scripts for Minecraft note blocks
* without needing to use any redstone or building to make your music.
* This class is independent of XSound.
*
@@ -128,7 +128,7 @@ public static XSound getSoundFromInstrument(@NotNull Instrument instrument) {
* The character paseed to this method is assumed to be uppercase,
* otherwise it needs to be {@code ch & 0x5f} manually.
*
- * https://minecraft.gamepedia.com/Note_Block#Notes
+ * https://minecraft.wiki/w/Note_Block#Notes
*
* @param ch the character of the note tone.
* @return the note tone or null if not found.
diff --git a/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XBlock.java b/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XBlock.java
index c57448a9f..e50b3a669 100644
--- a/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XBlock.java
+++ b/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XBlock.java
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
- * Copyright (c) 2022 Crypto Morin
+ * Copyright (c) 2023 Crypto Morin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XItemStack.java b/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XItemStack.java
index 3f236ae4f..766855b12 100644
--- a/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XItemStack.java
+++ b/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XItemStack.java
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
- * Copyright (c) 2021 Crypto Morin
+ * Copyright (c) 2023 Crypto Morin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -43,6 +43,9 @@
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.*;
+import org.bukkit.inventory.meta.trim.ArmorTrim;
+import org.bukkit.inventory.meta.trim.TrimMaterial;
+import org.bukkit.inventory.meta.trim.TrimPattern;
import org.bukkit.map.MapView;
import org.bukkit.material.MaterialData;
import org.bukkit.material.SpawnEgg;
@@ -71,10 +74,14 @@
* ConfigurationSection section = plugin.getConfig().getConfigurationSection("staffs.dragon-staff");
* ItemStack item = XItemStack.deserialize(section);
*
- * ItemStack: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/inventory/ItemStack.html
+ * ItemStack
*
* @author Crypto Morin
- * @version 6.0.0
+ * @version 7.3.3
+ * @see XMaterial
+ * @see XPotion
+ * @see SkullUtils
+ * @see XEnchantment
* @see ItemStack
*/
@SuppressWarnings("ALL")
@@ -93,6 +100,22 @@ public static boolean isDefaultItem(ItemStack item) {
return DEFAULT_MATERIAL.isSimilar(item);
}
+ private static BlockState safeBlockState(BlockStateMeta meta) {
+ // Due to a bug in the latest paper v1.9-1.10 (and some older v1.11) versions.
+ // java.lang.IllegalStateException: Missing blockState for BREWING_STAND_ITEM
+ // BREWING_STAND_ITEM, ENCHANTMENT_TABLE, REDSTONE_COMPARATOR
+ // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/diff/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java?until=b6ad714e853042def52620befe9bc85d0137cd71
+ try {
+ return meta.getBlockState();
+ } catch (IllegalStateException ex) {
+ if (ex.getMessage().toLowerCase(Locale.ENGLISH).contains("missing blockstate")) {
+ return null;
+ } else {
+ throw ex;
+ }
+ }
+ }
+
/**
* Writes an ItemStack object into a config.
* The config file will not save after the object is written.
@@ -150,7 +173,7 @@ public static void serialize(@NotNull ItemStack item, @NotNull ConfigurationSect
config.set("flags", flagNames);
}
- // Attributes - https://minecraft.gamepedia.com/Attribute
+ // Attributes - https://minecraft.wiki/w/Attribute
if (supports(13)) {
Multimap attributes = meta.getAttributeModifiers();
if (attributes != null) {
@@ -168,7 +191,7 @@ public static void serialize(@NotNull ItemStack item, @NotNull ConfigurationSect
}
if (meta instanceof BlockStateMeta) {
- BlockState state = ((BlockStateMeta) meta).getBlockState();
+ BlockState state = safeBlockState((BlockStateMeta) meta);
if (supports(11) && state instanceof ShulkerBox) {
ShulkerBox box = (ShulkerBox) state;
@@ -180,7 +203,7 @@ public static void serialize(@NotNull ItemStack item, @NotNull ConfigurationSect
}
} else if (state instanceof CreatureSpawner) {
CreatureSpawner cs = (CreatureSpawner) state;
- config.set("spawner", cs.getSpawnedType().name());
+ if (cs.getSpawnedType() != null) config.set("spawner", cs.getSpawnedType().name());
}
} else if (meta instanceof EnchantmentStorageMeta) {
EnchantmentStorageMeta book = (EnchantmentStorageMeta) meta;
@@ -210,7 +233,7 @@ public static void serialize(@NotNull ItemStack item, @NotNull ConfigurationSect
effects.add(effect.getType().getName() + ", " + effect.getDuration() + ", " + effect.getAmplifier());
}
- config.set("effects", effects);
+ if (!effects.isEmpty()) config.set("effects", effects);
PotionData potionData = potion.getBasePotionData();
config.set("base-effect", potionData.getType().name() + ", " + potionData.isExtended() + ", " + potionData.isUpgraded());
@@ -295,60 +318,80 @@ public static void serialize(@NotNull ItemStack item, @NotNull ConfigurationSect
view.set("unlimited-tracking", mapView.isUnlimitedTracking());
}
}
- } else if (supports(17)) {
- if (meta instanceof AxolotlBucketMeta) {
- AxolotlBucketMeta bucket = (AxolotlBucketMeta) meta;
- if (bucket.hasVariant()) config.set("color", bucket.getVariant().toString());
- }
- } else if (supports(16)) {
- if (meta instanceof CompassMeta) {
- CompassMeta compass = (CompassMeta) meta;
- ConfigurationSection subSection = config.createSection("lodestone");
- subSection.set("tracked", compass.isLodestoneTracked());
- if (compass.hasLodestone()) {
- Location location = compass.getLodestone();
- subSection.set("location.world", location.getWorld().getName());
- subSection.set("location.x", location.getX());
- subSection.set("location.y", location.getY());
- subSection.set("location.z", location.getZ());
+ } else {
+ if (supports(20)) {
+ if (meta instanceof ArmorMeta) {
+ ArmorMeta armorMeta = (ArmorMeta) meta;
+ if (armorMeta.hasTrim()) {
+ ArmorTrim trim = armorMeta.getTrim();
+ ConfigurationSection trimConfig = config.createSection("trim");
+ trimConfig.set("material", trim.getMaterial().getKey().getNamespace() + ':' + trim.getMaterial().getKey().getKey());
+ trimConfig.set("pattern", trim.getPattern().getKey().getNamespace() + ':' + trim.getPattern().getKey().getKey());
+ }
}
}
- } else if (supports(14)) {
- if (meta instanceof CrossbowMeta) {
- CrossbowMeta crossbow = (CrossbowMeta) meta;
- int i = 0;
- for (ItemStack projectiles : crossbow.getChargedProjectiles()) {
- serialize(projectiles, config.getConfigurationSection("projectiles." + i));
- i++;
- }
- } else if (meta instanceof TropicalFishBucketMeta) {
- TropicalFishBucketMeta tropical = (TropicalFishBucketMeta) meta;
- config.set("pattern", tropical.getPattern().name());
- config.set("color", tropical.getBodyColor().name());
- config.set("pattern-color", tropical.getPatternColor().name());
- } else if (meta instanceof SuspiciousStewMeta) {
- SuspiciousStewMeta stew = (SuspiciousStewMeta) meta;
- List customEffects = stew.getCustomEffects();
- List effects = new ArrayList<>(customEffects.size());
- for (PotionEffect effect : customEffects) {
- effects.add(effect.getType().getName() + ", " + effect.getDuration() + ", " + effect.getAmplifier());
+ if (supports(17)) {
+ if (meta instanceof AxolotlBucketMeta) {
+ AxolotlBucketMeta bucket = (AxolotlBucketMeta) meta;
+ if (bucket.hasVariant()) config.set("color", bucket.getVariant().toString());
}
+ }
- config.set("effects", effects);
+ if (supports(16)) {
+ if (meta instanceof CompassMeta) {
+ CompassMeta compass = (CompassMeta) meta;
+ ConfigurationSection subSection = config.createSection("lodestone");
+ subSection.set("tracked", compass.isLodestoneTracked());
+ if (compass.hasLodestone()) {
+ Location location = compass.getLodestone();
+ subSection.set("location.world", location.getWorld().getName());
+ subSection.set("location.x", location.getX());
+ subSection.set("location.y", location.getY());
+ subSection.set("location.z", location.getZ());
+ }
+ }
}
- } else if (!supports(13)) {
- // Spawn Eggs
- if (supports(11)) {
- if (meta instanceof SpawnEggMeta) {
- SpawnEggMeta spawnEgg = (SpawnEggMeta) meta;
- config.set("creature", spawnEgg.getSpawnedType().getName());
+
+ if (supports(14)) {
+ if (meta instanceof CrossbowMeta) {
+ CrossbowMeta crossbow = (CrossbowMeta) meta;
+ int i = 0;
+ for (ItemStack projectiles : crossbow.getChargedProjectiles()) {
+ serialize(projectiles, config.getConfigurationSection("projectiles." + i));
+ i++;
+ }
+ } else if (meta instanceof TropicalFishBucketMeta) {
+ TropicalFishBucketMeta tropical = (TropicalFishBucketMeta) meta;
+ config.set("pattern", tropical.getPattern().name());
+ config.set("color", tropical.getBodyColor().name());
+ config.set("pattern-color", tropical.getPatternColor().name());
+ } else if (meta instanceof SuspiciousStewMeta) {
+ SuspiciousStewMeta stew = (SuspiciousStewMeta) meta;
+ List customEffects = stew.getCustomEffects();
+ List effects = new ArrayList<>(customEffects.size());
+
+ for (PotionEffect effect : customEffects) {
+ effects.add(effect.getType().getName() + ", " + effect.getDuration() + ", " + effect.getAmplifier());
+ }
+
+ config.set("effects", effects);
}
- } else {
- MaterialData data = item.getData();
- if (data instanceof SpawnEgg) {
- SpawnEgg spawnEgg = (SpawnEgg) data;
- config.set("creature", spawnEgg.getSpawnedType().getName());
+ }
+
+ if (!supports(13)) {
+ // Spawn Eggs
+ if (supports(11)) {
+ if (meta instanceof SpawnEggMeta) {
+ SpawnEggMeta spawnEgg = (SpawnEggMeta) meta;
+ config.set("creature", spawnEgg.getSpawnedType().getName());
+ }
+ } else {
+ MaterialData data = item.getData();
+ if (data instanceof SpawnEgg) {
+ SpawnEgg spawnEgg = (SpawnEgg) data;
+ config.set("creature", spawnEgg.getSpawnedType().getName());
+ }
}
}
}
@@ -533,14 +576,15 @@ public static ItemStack edit(@NotNull ItemStack item,
if (unsupportedMaterialCondition.hasSolution()) material = unsupportedMaterialCondition.solution;
else throw unsupportedMaterialCondition;
}
-// if (XMaterialUtil.INVENTORY_NOT_DISPLAYABLE.isTagged(material)) {
-// UnAcceptableMaterialCondition unsupportedMaterialCondition = new UnAcceptableMaterialCondition(material, UnAcceptableMaterialCondition.Reason.NOT_DISPLAYABLE);
-// if (restart == null) throw unsupportedMaterialCondition;
-// restart.accept(unsupportedMaterialCondition);
-//
-// if (unsupportedMaterialCondition.hasSolution()) material = unsupportedMaterialCondition.solution;
-// else throw unsupportedMaterialCondition;
-// }
+ if (XMaterialUtil.INVENTORY_NOT_DISPLAYABLE.isTagged(material)) {
+ UnAcceptableMaterialCondition unsupportedMaterialCondition = new UnAcceptableMaterialCondition(material, UnAcceptableMaterialCondition.Reason.NOT_DISPLAYABLE);
+ if (restart == null) throw unsupportedMaterialCondition;
+ restart.accept(unsupportedMaterialCondition);
+
+ if (unsupportedMaterialCondition.hasSolution()) material = unsupportedMaterialCondition.solution;
+ else throw unsupportedMaterialCondition;
+ }
+
material.setType(item);
}
@@ -580,7 +624,6 @@ public static ItemStack edit(@NotNull ItemStack item,
BannerMeta banner = (BannerMeta) meta;
ConfigurationSection patterns = config.getConfigurationSection("patterns");
- //System.out.println("patters v2: " + patterns);
if (patterns != null) {
for (String pattern : patterns.getKeys(false)) {
PatternType type = PatternType.getByIdentifier(pattern);
@@ -636,13 +679,17 @@ public static ItemStack edit(@NotNull ItemStack item,
}
} else if (meta instanceof BlockStateMeta) {
BlockStateMeta bsm = (BlockStateMeta) meta;
- BlockState state = bsm.getBlockState();
+ BlockState state = safeBlockState(bsm);
if (state instanceof CreatureSpawner) {
+ // Do we still need this? XMaterial handles it, doesn't it?
CreatureSpawner spawner = (CreatureSpawner) state;
- spawner.setSpawnedType(Enums.getIfPresent(EntityType.class, config.getString("spawner").toUpperCase(Locale.ENGLISH)).orNull());
- spawner.update(true);
- bsm.setBlockState(spawner);
+ String spawnerStr = config.getString("spawner");
+ if (!Strings.isNullOrEmpty(spawnerStr)) {
+ spawner.setSpawnedType(Enums.getIfPresent(EntityType.class, spawnerStr.toUpperCase(Locale.ENGLISH)).orNull());
+ spawner.update(true);
+ bsm.setBlockState(spawner);
+ }
} else if (supports(11) && state instanceof ShulkerBox) {
ConfigurationSection shulkerSection = config.getConfigurationSection("contents");
if (shulkerSection != null) {
@@ -663,7 +710,6 @@ public static ItemStack edit(@NotNull ItemStack item,
banner.setBaseColor(DyeColor.WHITE);
}
- //System.out.println("patterns are " + patterns);
if (patterns != null) {
for (String pattern : patterns.getKeys(false)) {
PatternType type = PatternType.getByIdentifier(pattern);
@@ -695,15 +741,17 @@ public static ItemStack edit(@NotNull ItemStack item,
.or(FireworkEffect.Type.STAR));
ConfigurationSection colorsSection = fw.getConfigurationSection("colors");
- List fwColors = colorsSection.getStringList("base");
- List colors = new ArrayList<>(fwColors.size());
- for (String colorStr : fwColors) colors.add(parseColor(colorStr));
- builder.withColor(colors);
-
- fwColors = colorsSection.getStringList("fade");
- colors = new ArrayList<>(fwColors.size());
- for (String colorStr : fwColors) colors.add(parseColor(colorStr));
- builder.withFade(colors);
+ if (colorsSection != null) {
+ List fwColors = colorsSection.getStringList("base");
+ List colors = new ArrayList<>(fwColors.size());
+ for (String colorStr : fwColors) colors.add(parseColor(colorStr));
+ builder.withColor(colors);
+
+ fwColors = colorsSection.getStringList("fade");
+ colors = new ArrayList<>(fwColors.size());
+ for (String colorStr : fwColors) colors.add(parseColor(colorStr));
+ builder.withFade(colors);
+ }
firework.addEffect(builder.build());
}
@@ -752,83 +800,110 @@ public static ItemStack edit(@NotNull ItemStack item,
mapView.setUnlimitedTracking(view.getBoolean("unlimited-tracking"));
ConfigurationSection centerSection = view.getConfigurationSection("center");
- mapView.setCenterX(centerSection.getInt("x"));
- mapView.setCenterZ(centerSection.getInt("z"));
+ if (centerSection != null) {
+ mapView.setCenterX(centerSection.getInt("x"));
+ mapView.setCenterZ(centerSection.getInt("z"));
+ }
map.setMapView(mapView);
}
}
}
}
- } else if (supports(17)) {
- if (meta instanceof AxolotlBucketMeta) {
- AxolotlBucketMeta bucket = (AxolotlBucketMeta) meta;
- String variantStr = config.getString("color");
- if (variantStr != null) {
- Axolotl.Variant variant = Enums.getIfPresent(Axolotl.Variant.class, variantStr.toUpperCase(Locale.ENGLISH)).or(Axolotl.Variant.BLUE);
- bucket.setVariant(variant);
+ } else {
+ if (supports(20)) {
+ if (meta instanceof ArmorMeta) {
+ ArmorMeta armorMeta = (ArmorMeta) meta;
+ if (config.contains("trim")) {
+ ConfigurationSection trim = config.getConfigurationSection("trim");
+ TrimMaterial trimMaterial = Registry.TRIM_MATERIAL.get(NamespacedKey.fromString(trim.getString("material")));
+ TrimPattern trimPattern = Registry.TRIM_PATTERN.get(NamespacedKey.fromString(trim.getString("pattern")));
+ armorMeta.setTrim(new ArmorTrim(trimMaterial, trimPattern));
+ }
}
}
- } else if (supports(16)) {
- if (meta instanceof CompassMeta) {
- CompassMeta compass = (CompassMeta) meta;
- compass.setLodestoneTracked(config.getBoolean("tracked"));
-
- ConfigurationSection lodestone = config.getConfigurationSection("lodestone");
- if (lodestone != null) {
- World world = Bukkit.getWorld(lodestone.getString("world"));
- double x = lodestone.getDouble("x");
- double y = lodestone.getDouble("y");
- double z = lodestone.getDouble("z");
- compass.setLodestone(new Location(world, x, y, z));
+
+ if (supports(17)) {
+ if (meta instanceof AxolotlBucketMeta) {
+ AxolotlBucketMeta bucket = (AxolotlBucketMeta) meta;
+ String variantStr = config.getString("color");
+ if (variantStr != null) {
+ Axolotl.Variant variant = Enums.getIfPresent(Axolotl.Variant.class, variantStr.toUpperCase(Locale.ENGLISH)).or(Axolotl.Variant.BLUE);
+ bucket.setVariant(variant);
+ }
}
}
- } else if (supports(15)) {
- if (meta instanceof SuspiciousStewMeta) {
- SuspiciousStewMeta stew = (SuspiciousStewMeta) meta;
- for (String effects : config.getStringList("effects")) {
- XPotion.Effect effect = XPotion.parseEffect(effects);
- if (effect.hasChance()) stew.addCustomEffect(effect.getEffect(), true);
+
+ if (supports(16)) {
+ if (meta instanceof CompassMeta) {
+ CompassMeta compass = (CompassMeta) meta;
+ compass.setLodestoneTracked(config.getBoolean("tracked"));
+
+ ConfigurationSection lodestone = config.getConfigurationSection("lodestone");
+ if (lodestone != null) {
+ World world = Bukkit.getWorld(lodestone.getString("world"));
+ double x = lodestone.getDouble("x");
+ double y = lodestone.getDouble("y");
+ double z = lodestone.getDouble("z");
+ compass.setLodestone(new Location(world, x, y, z));
+ }
}
}
- } else if (supports(14)) {
- if (meta instanceof CrossbowMeta) {
- CrossbowMeta crossbow = (CrossbowMeta) meta;
- for (String projectiles : config.getConfigurationSection("projectiles").getKeys(false)) {
- ItemStack projectile = deserialize(config.getConfigurationSection("projectiles." + projectiles));
- crossbow.addChargedProjectile(projectile);
+
+ if (supports(15)) {
+ if (meta instanceof SuspiciousStewMeta) {
+ SuspiciousStewMeta stew = (SuspiciousStewMeta) meta;
+ for (String effects : config.getStringList("effects")) {
+ XPotion.Effect effect = XPotion.parseEffect(effects);
+ if (effect.hasChance()) stew.addCustomEffect(effect.getEffect(), true);
+ }
}
- } else if (meta instanceof TropicalFishBucketMeta) {
- TropicalFishBucketMeta tropical = (TropicalFishBucketMeta) meta;
- DyeColor color = Enums.getIfPresent(DyeColor.class, config.getString("color")).or(DyeColor.WHITE);
- DyeColor patternColor = Enums.getIfPresent(DyeColor.class, config.getString("pattern-color")).or(DyeColor.WHITE);
- TropicalFish.Pattern pattern = Enums.getIfPresent(TropicalFish.Pattern.class, config.getString("pattern")).or(TropicalFish.Pattern.BETTY);
-
- tropical.setBodyColor(color);
- tropical.setPatternColor(patternColor);
- tropical.setPattern(pattern);
}
- // Apparently Suspicious Stew was never added in 1.14
- } else if (!supports(13)) {
- // Spawn Eggs
- if (supports(11)) {
- if (meta instanceof SpawnEggMeta) {
- String creatureName = config.getString("creature");
- if (!Strings.isNullOrEmpty(creatureName)) {
- SpawnEggMeta spawnEgg = (SpawnEggMeta) meta;
- com.google.common.base.Optional creature = Enums.getIfPresent(EntityType.class, creatureName.toUpperCase(Locale.ENGLISH));
- if (creature.isPresent()) spawnEgg.setSpawnedType(creature.get());
+
+ if (supports(14)) {
+ if (meta instanceof CrossbowMeta) {
+ CrossbowMeta crossbow = (CrossbowMeta) meta;
+ ConfigurationSection projectiles = config.getConfigurationSection("projectiles");
+ if (projectiles != null) {
+ for (String projectile : projectiles.getKeys(false)) {
+ ItemStack projectileItem = deserialize(config.getConfigurationSection("projectiles." + projectile));
+ crossbow.addChargedProjectile(projectileItem);
+ }
}
+ } else if (meta instanceof TropicalFishBucketMeta) {
+ TropicalFishBucketMeta tropical = (TropicalFishBucketMeta) meta;
+ DyeColor color = Enums.getIfPresent(DyeColor.class, config.getString("color")).or(DyeColor.WHITE);
+ DyeColor patternColor = Enums.getIfPresent(DyeColor.class, config.getString("pattern-color")).or(DyeColor.WHITE);
+ TropicalFish.Pattern pattern = Enums.getIfPresent(TropicalFish.Pattern.class, config.getString("pattern")).or(TropicalFish.Pattern.BETTY);
+
+ tropical.setBodyColor(color);
+ tropical.setPatternColor(patternColor);
+ tropical.setPattern(pattern);
}
- } else {
- MaterialData data = item.getData();
- if (data instanceof SpawnEgg) {
- String creatureName = config.getString("creature");
- if (!Strings.isNullOrEmpty(creatureName)) {
- SpawnEgg spawnEgg = (SpawnEgg) data;
- com.google.common.base.Optional creature = Enums.getIfPresent(EntityType.class, creatureName.toUpperCase(Locale.ENGLISH));
- if (creature.isPresent()) spawnEgg.setSpawnedType(creature.get());
- item.setData(data);
+ }
+
+ // Apparently Suspicious Stew was never added in 1.14
+ if (!supports(13)) {
+ // Spawn Eggs
+ if (supports(11)) {
+ if (meta instanceof SpawnEggMeta) {
+ String creatureName = config.getString("creature");
+ if (!Strings.isNullOrEmpty(creatureName)) {
+ SpawnEggMeta spawnEgg = (SpawnEggMeta) meta;
+ com.google.common.base.Optional creature = Enums.getIfPresent(EntityType.class, creatureName.toUpperCase(Locale.ENGLISH));
+ if (creature.isPresent()) spawnEgg.setSpawnedType(creature.get());
+ }
+ }
+ } else {
+ MaterialData data = item.getData();
+ if (data instanceof SpawnEgg) {
+ String creatureName = config.getString("creature");
+ if (!Strings.isNullOrEmpty(creatureName)) {
+ SpawnEgg spawnEgg = (SpawnEgg) data;
+ com.google.common.base.Optional creature = Enums.getIfPresent(EntityType.class, creatureName.toUpperCase(Locale.ENGLISH));
+ if (creature.isPresent()) spawnEgg.setSpawnedType(creature.get());
+ item.setData(data);
+ }
}
}
}
@@ -931,7 +1006,7 @@ public static ItemStack edit(@NotNull ItemStack item,
meta.addItemFlags(ITEM_FLAGS);
}
- // Atrributes - https://minecraft.gamepedia.com/Attribute
+ // Atrributes - https://minecraft.wiki/w/Attribute
if (supports(13)) {
ConfigurationSection attributes = config.getConfigurationSection("attributes");
if (attributes != null) {
@@ -948,7 +1023,7 @@ public static ItemStack edit(@NotNull ItemStack item,
AttributeModifier modifier = new AttributeModifier(
id,
section.getString("name"),
- section.getInt("amount"),
+ section.getDouble("amount"),
Enums.getIfPresent(AttributeModifier.Operation.class, section.getString("operation"))
.or(AttributeModifier.Operation.ADD_NUMBER),
slot);
@@ -1069,8 +1144,8 @@ public static List addItems(@NotNull Inventory inventory, boolean spl
* CraftInventory
*
* @param inventory the inventory to add the items to.
- * @param split if it should check for the inventory stack size {@link Inventory#getMaxStackSize()} or
- * item's max stack size {@link ItemStack#getMaxStackSize()} when putting items. This is useful when
+ * @param split false if it should check for the inventory stack size {@link Inventory#getMaxStackSize()} or
+ * true for item's max stack size {@link ItemStack#getMaxStackSize()} when putting items. This is useful when
* you're adding stacked tools such as swords that you'd like to split them to other slots.
* @param modifiableSlots the slots that are allowed to be used for adding the items, otherwise null to allow all slots.
* @param items the items to add.
@@ -1086,7 +1161,7 @@ public static List addItems(@NotNull Inventory inventory, boolean spl
List leftOvers = new ArrayList<>(items.length);
// No other optimized way to access this using Bukkit API...
- // We could pass the length to individual methods so they could also use getItem() which
+ // We could pass the length to individual methods, so they could also use getItem() which
// skips parsing all the items in the inventory if not needed, but that's just too much.
// Note: This is not the same as Inventory#getSize()
int invSize = inventory.getStorageContents().length;
@@ -1094,12 +1169,13 @@ public static List addItems(@NotNull Inventory inventory, boolean spl
for (ItemStack item : items) {
int lastPartial = 0;
+ int maxAmount = split ? item.getMaxStackSize() : inventory.getMaxStackSize();
while (true) {
// Check if there is a similar item that can be stacked before using free slots.
int firstPartial = lastPartial >= invSize ? -1 : firstPartial(inventory, item, lastPartial, modifiableSlots);
- if (firstPartial == -1) {
- // Start adding items to left overs if there are no partial and empty slots
+ if (firstPartial == -1) { // No partial items found
+ // Start adding items to leftovers if there are no partial and empty slots
// -1 means that there are no empty slots left.
if (lastEmpty != -1) lastEmpty = firstEmpty(inventory, lastEmpty, modifiableSlots);
if (lastEmpty == -1) {
@@ -1109,26 +1185,22 @@ public static List addItems(@NotNull Inventory inventory, boolean spl
// Avoid firstPartial() for checking again for no reason, since if we're already checking
// for free slots, that means there are no partials even left.
- lastPartial = invSize + 1;
+ lastPartial = Integer.MAX_VALUE;
- int maxSize = split ? item.getMaxStackSize() : inventory.getMaxStackSize();
int amount = item.getAmount();
- if (amount <= maxSize) {
+ if (amount <= maxAmount) {
inventory.setItem(lastEmpty, item);
break;
} else {
ItemStack copy = item.clone();
- copy.setAmount(maxSize);
+ copy.setAmount(maxAmount);
inventory.setItem(lastEmpty, copy);
- item.setAmount(amount - maxSize);
+ item.setAmount(amount - maxAmount);
}
if (++lastEmpty == invSize) lastEmpty = -1;
} else {
ItemStack partialItem = inventory.getItem(firstPartial);
- int maxAmount = split ? partialItem.getMaxStackSize() : inventory.getMaxStackSize();
- int partialAmount = partialItem.getAmount();
- int amount = item.getAmount();
- int sum = amount + partialAmount;
+ int sum = item.getAmount() + partialItem.getAmount();
if (sum <= maxAmount) {
partialItem.setAmount(sum);
diff --git a/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XMaterialUtil.java b/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XMaterialUtil.java
index f22b1b328..e46fa06ee 100644
--- a/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XMaterialUtil.java
+++ b/platform/platform-bukkit/src/main/java/taboolib/library/xseries/XMaterialUtil.java
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
- * Copyright (c) 2022 Crypto Morin
+ * Copyright (c) 2023 Crypto Morin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,11 +22,15 @@
package taboolib.library.xseries;
import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import taboolib.common.Isolated;
+import java.lang.reflect.Field;
import java.util.*;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
@SuppressWarnings("CommentedOutCode")
@Isolated
@@ -317,6 +321,11 @@ public final class XMaterialUtil> {
*/
@NotNull
public static final XMaterialUtil FENCES;
+ /**
+ * Tag representing all possible variants of filled cauldron
+ */
+ @NotNull
+ public static final XMaterialUtil FILLED_CAULDRONS;
/**
* Tag representing all possible variants fire
*/
@@ -794,6 +803,11 @@ public final class XMaterialUtil> {
*/
@NotNull
public static final XMaterialUtil VALID_SPAWN;
+ /**
+ * Tag representing all possible variants of wall hanging sign
+ */
+ @NotNull
+ public static final XMaterialUtil WALL_HANGING_SIGNS;
/**
* Tag representing all possible block types that can override a wall post creation
*/
@@ -804,6 +818,11 @@ public final class XMaterialUtil> {
*/
@NotNull
public static final XMaterialUtil WALL_SIGNS;
+ /**
+ * Tag representing all possible types of wall torches
+ */
+ @NotNull
+ public static final XMaterialUtil WALL_TORCHES;
/**
* Tag representing all different types of walls
*/
@@ -1073,6 +1092,7 @@ public final class XMaterialUtil> {
static { // wooded material
STANDING_SIGNS = new XMaterialUtil<>(findAllWoodTypes("SIGN"));
WALL_SIGNS = new XMaterialUtil<>(findAllWoodTypes("WALL_SIGN"));
+ WALL_HANGING_SIGNS = new XMaterialUtil<>(findAllWoodTypes("WALL_HANGING_SIGN"));
HANGING_SIGNS = new XMaterialUtil<>(findAllWoodTypes("HANGING_SIGN"));
WOODEN_PRESSURE_PLATES = new XMaterialUtil<>(findAllWoodTypes("PRESSURE_PLATE"));
WOODEN_DOORS = new XMaterialUtil<>(findAllWoodTypes("DOOR"));
@@ -1130,6 +1150,9 @@ public final class XMaterialUtil> {
WALL_HEADS = new XMaterialUtil<>(XMaterial.class, new XMaterialUtil<>(findMaterialsEndingWith("WALL_HEAD")),
new XMaterialUtil<>(XMaterial.WITHER_SKELETON_WALL_SKULL, XMaterial.SKELETON_WALL_SKULL));
+ WALL_TORCHES = new XMaterialUtil<>(XMaterial.WALL_TORCH,
+ XMaterial.SOUL_WALL_TORCH,
+ XMaterial.REDSTONE_WALL_TORCH);
WALLS = new XMaterialUtil<>(XMaterial.POLISHED_DEEPSLATE_WALL,
XMaterial.NETHER_BRICK_WALL,
XMaterial.POLISHED_BLACKSTONE_WALL,
@@ -1200,6 +1223,9 @@ public final class XMaterialUtil> {
XMaterial.PUMPKIN_STEM);
CAMPFIRES = new XMaterialUtil<>(XMaterial.CAMPFIRE,
XMaterial.SOUL_CAMPFIRE);
+ FILLED_CAULDRONS = new XMaterialUtil<>(XMaterial.LAVA_CAULDRON,
+ XMaterial.POWDER_SNOW_CAULDRON,
+ XMaterial.WATER_CAULDRON);
CAULDRONS = new XMaterialUtil<>(XMaterial.CAULDRON,
XMaterial.LAVA_CAULDRON,
XMaterial.POWDER_SNOW_CAULDRON,
@@ -1308,7 +1334,8 @@ public final class XMaterialUtil> {
XMaterial.POTTED_JUNGLE_SAPLING,
XMaterial.POTTED_BIRCH_SAPLING,
XMaterial.POTTED_MANGROVE_PROPAGULE,
- XMaterial.POTTED_CHERRY_SAPLING);
+ XMaterial.POTTED_CHERRY_SAPLING,
+ XMaterial.POTTED_TORCHFLOWER);
FOX_FOOD = new XMaterialUtil<>(XMaterial.GLOW_BERRIES,
XMaterial.SWEET_BERRIES);
FOXES_SPAWNABLE_ON = new XMaterialUtil<>(XMaterial.SNOW,
@@ -1554,7 +1581,7 @@ public final class XMaterialUtil> {
XMaterial.LARGE_FERN,
XMaterial.LILAC,
XMaterial.ROSE_BUSH,
- XMaterial.GRASS);
+ XMaterial.SHORT_GRASS);
SMALL_DRIPLEAF_PLACEABLE = new XMaterialUtil<>(XMaterial.CLAY,
XMaterial.MOSS_BLOCK);
NON_FLAMMABLE_WOOD = new XMaterialUtil<>(XMaterial.CRIMSON_PLANKS,
@@ -2216,7 +2243,7 @@ public final class XMaterialUtil> {
XMaterial.SMALL_DRIPLEAF,
XMaterial.LOOM,
XMaterial.BEEHIVE,
- XMaterial.GRASS,
+ XMaterial.SHORT_GRASS,
XMaterial.HANGING_ROOTS,
XMaterial.CHORUS_FLOWER,
XMaterial.ATTACHED_PUMPKIN_STEM,
@@ -2262,10 +2289,15 @@ public final class XMaterialUtil> {
FIRE = new XMaterialUtil<>(XMaterial.FIRE, XMaterial.SOUL_FIRE);
FLUID = new XMaterialUtil<>(XMaterial.LAVA, XMaterial.WATER);
- INVENTORY_NOT_DISPLAYABLE = new XMaterialUtil<>(XMaterial.class, AIR, FIRE, FLUID, PORTALS, WALL_SIGNS,
- CORAL_FANS, WALL_HEADS, CANDLE_CAKES, WALL_BANNERS, FLOWER_POTS,
- new XMaterialUtil<>(XMaterial.SWEET_BERRY_BUSH, XMaterial.CHORUS_PLANT, XMaterial.KELP_PLANT,
- XMaterial.CAVE_VINES_PLANT, XMaterial.TWISTING_VINES_PLANT, XMaterial.WEEPING_VINES_PLANT));
+ INVENTORY_NOT_DISPLAYABLE = new XMaterialUtil<>(XMaterial.class, AIR, CAVE_VINES, FILLED_CAULDRONS, FIRE, FLUID, PORTALS,
+ WALL_SIGNS, WALL_HANGING_SIGNS, WALL_TORCHES, ALIVE_CORAL_WALL_FANS, DEAD_CORAL_WALL_FANS, WALL_HEADS,
+ CANDLE_CAKES, WALL_BANNERS, FLOWER_POTS.without(XMaterial.FLOWER_POT), CROPS.without(XMaterial.WHEAT),
+ new XMaterialUtil<>(XMaterial.BIG_DRIPLEAF_STEM, XMaterial.SWEET_BERRY_BUSH, XMaterial.KELP_PLANT,
+ XMaterial.FROSTED_ICE, XMaterial.ATTACHED_MELON_STEM, XMaterial.ATTACHED_PUMPKIN_STEM,
+ XMaterial.COCOA, XMaterial.MOVING_PISTON, XMaterial.PISTON_HEAD, XMaterial.PITCHER_CROP,
+ XMaterial.POWDER_SNOW, XMaterial.REDSTONE_WIRE, XMaterial.TALL_SEAGRASS, XMaterial.TRIPWIRE,
+ XMaterial.TORCHFLOWER_CROP, XMaterial.BUBBLE_COLUMN, XMaterial.TWISTING_VINES_PLANT,
+ XMaterial.WEEPING_VINES_PLANT, XMaterial.BAMBOO_SAPLING));
}
@NotNull
@@ -2276,12 +2308,156 @@ private XMaterialUtil(@NotNull T... values) {
this.values = Collections.unmodifiableSet(EnumSet.copyOf(Arrays.asList(values)));
}
+ /**
+ * Compiles a list of string checkers for various classes like {@link XMaterial}, {@link XSound}, etc.
+ * Mostly used for configs.
+ *
+ * Supports {@link String#contains} {@code CONTAINS:NAME} and Regular Expression {@code REGEX:PATTERN} formats.
+ *
+ * Example:
+ *
+ * XMaterial material = {@link XMaterial#matchXMaterial(ItemStack)};
+ * if (XMaterialUtil.anyMatch(XMaterialUtil.stringMatcher(plugin.getConfig().getStringList("disabled-items"), null)) return;
+ *
+ *
+ * {@code CONTAINS} Examples:
+ *
+ * {@code "CONTAINS:CHEST" -> CHEST, ENDERCHEST, TRAPPED_CHEST -> true}
+ * {@code "cOnTaINS:dYe" -> GREEN_DYE, YELLOW_DYE, BLUE_DYE, INK_SACK -> true}
+ *
+ *
+ * {@code REGEX} Examples
+ *
+ * {@code "REGEX:^.+_.+_.+$" -> Every Material with 3 underlines or more: SHULKER_SPAWN_EGG, SILVERFISH_SPAWN_EGG, SKELETON_HORSE_SPAWN_EGG}
+ * {@code "REGEX:^.{1,3}$" -> Material names that have 3 letters only: BED, MAP, AIR}
+ *
+ *
+ * The reason that there are tags for {@code CONTAINS} and {@code REGEX} is for the performance.
+ * Server owners should be advised to avoid using {@code REGEX} tag if they can use the {@code CONTAINS} tag instead.
+ *
+ * Want to learn RegEx? You can mess around in RegExr website.
+ *
+ * @param elements the material names to check base material on.
+ * @return a compiled list of enum matchers.
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public static List> stringMatcher(@Nullable Collection elements,
+ @Nullable Collection errors) {
+ if (elements == null || elements.isEmpty()) return new ArrayList<>();
+ List> matchers = new ArrayList<>(elements.size());
+
+ for (String comp : elements) {
+ String checker = comp.toUpperCase(Locale.ENGLISH);
+ if (checker.startsWith("CONTAINS:")) {
+ comp = XMaterial.format(checker.substring(9));
+ matchers.add(new Matcher.TextMatcher<>(comp, true));
+ continue;
+ }
+ if (checker.startsWith("REGEX:")) {
+ comp = comp.substring(6);
+ try {
+ matchers.add(new Matcher.RegexMatcher<>(Pattern.compile(comp)));
+ } catch (Throwable e) {
+ if (errors != null) errors.add(new Matcher.Error(comp, "REGEX", e));
+ }
+ continue;
+ }
+ if (checker.startsWith("TAG:")) {
+ comp = XMaterial.format(comp.substring(4));
+ try {
+ Field field = XMaterialUtil.class.getField(comp);
+ XMaterialUtil> obj = (XMaterialUtil>) field.get(null);
+ matchers.add(new Matcher.XMaterialUtilMatcher(obj));
+ } catch (Throwable e) {
+ if (errors != null) errors.add(new Matcher.Error(comp, "TAG", e));
+ }
+ }
+
+ matchers.add(new Matcher.TextMatcher<>(comp, false));
+ }
+
+ return matchers;
+ }
+
+ public static boolean anyMatch(T target, Collection> matchers) {
+ return matchers.stream().anyMatch(x -> x.matches(target));
+ }
+
+ @Isolated
+ public abstract static class Matcher {
+
+ @Isolated
+ public static final class Error extends RuntimeException {
+ public final String matcher;
+
+ public Error(String matcher, String message, Throwable cause) {
+ super(message, cause);
+ this.matcher = matcher;
+ }
+ }
+
+ public abstract boolean matches(T object);
+
+ @Isolated
+ public static final class TextMatcher extends Matcher {
+
+ public final String text;
+ public final boolean contains;
+
+ public TextMatcher(String text, boolean contains) {
+ this.text = text;
+ this.contains = contains;
+ }
+
+ @Override
+ public boolean matches(T object) {
+ String name = object instanceof Enum ? ((Enum>) object).name() : object.toString();
+ return contains ? name.contains(this.text) : name.equals(this.text);
+ }
+ }
+
+ @Isolated
+ public static final class RegexMatcher extends Matcher {
+
+ public final Pattern regex;
+
+ public RegexMatcher(Pattern regex) {
+ this.regex = regex;
+ }
+
+ @Override
+ public boolean matches(T object) {
+ String name = object instanceof Enum ? ((Enum>) object).name() : object.toString();
+ return regex.matcher(name).matches();
+ }
+ }
+
+ @Isolated
+ public static final class XMaterialUtilMatcher> extends Matcher {
+
+ public final XMaterialUtil matcher;
+
+ public XMaterialUtilMatcher(XMaterialUtil matcher) {
+ this.matcher = matcher;
+ }
+
+ @Override
+ public boolean matches(T object) {
+ return matcher.isTagged(object);
+ }
+ }
+ }
+
@SafeVarargs
private XMaterialUtil(@NotNull Class clazz, @NotNull XMaterialUtil... values) {
this.values = EnumSet.noneOf(clazz);
this.inheritFrom(values);
}
+ private XMaterialUtil(@NotNull Set values) {
+ this.values = Collections.unmodifiableSet(values);
+ }
+
private static XMaterial[] findAllColors(String material) {
String[] colorPrefixes = {"ORANGE", "LIGHT_BLUE", "GRAY", "BLACK", "MAGENTA", "PINK", "BLUE",
"GREEN", "CYAN", "PURPLE", "YELLOW", "LIME", "LIGHT_GRAY", "WHITE", "BROWN", "RED"};
@@ -2607,6 +2783,14 @@ public boolean isTagged(@Nullable T value) {
return value != null && this.values.contains(value);
}
+ @SafeVarargs
+ private final XMaterialUtil without(T... without) {
+ Set ignore = new HashSet<>();
+ Collections.addAll(ignore, without);
+ Set newValues = values.stream().filter(t -> !ignore.contains(t)).collect(Collectors.toSet());
+ return new XMaterialUtil<>(newValues);
+ }
+
@SafeVarargs
private final XMaterialUtil inheritFrom(@NotNull XMaterialUtil... values) {
// Copied because of Collections.unmodifiableSet.