Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ _Published one day_
```

To hide _all_ attributes from the item, use `hideAllAttributes()`.

#### [`ItemUtils`](https://zdevelopers.github.io/QuartzLib/fr/zcraft/quartzlib/tools/items/ItemUtils.html)

- We added a [`asDye`](https://zdevelopers.github.io/QuartzLib/fr/zcraft/quartzlib/tools/items/ItemUtils.html#asDye-org.bukkit.ChatColor-) method to convert a `ChatColor` to its closest `DyeColor` equivalent.

- We added two `colorize` methods to `ItemUtils` to convert either [a dye](https://zdevelopers.github.io/QuartzLib/fr/zcraft/quartzlib/tools/items/ItemUtils.html#colorize-fr.zcraft.quartzlib.tools.items.ColorableMaterial-org.bukkit.DyeColor-) or [a chat color](https://zdevelopers.github.io/QuartzLib/fr/zcraft/quartzlib/tools/items/ItemUtils.html#colorize-fr.zcraft.quartzlib.tools.items.ColorableMaterial-org.bukkit.ChatColor-) to a colored block dynamically. As example,

```java
ItemUtils.colorize(ColorableMaterial.GLAZED_TERRACOTTA, DyeColor.LIME)
```

will return `Material.LIME_GLAZED_TERRACOTTA`.

#### Tests

Expand Down
1 change: 1 addition & 0 deletions checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
</module>

<module name="TreeWalker">
<module name="SuppressWarningsHolder"/>
<module name="SuppressWarnings">
<property name="id" value="checkstyle:suppresswarnings"/>
</module>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright or © or Copr. QuartzLib contributors (2015 - 2020)
*
* This software is governed by the CeCILL-B license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL-B
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-B license and that you accept its terms.
*/

package fr.zcraft.quartzlib.tools.items;

import org.bukkit.ChatColor;
import org.bukkit.DyeColor;
import org.bukkit.Material;

/**
* A {@link Material} with color variants.
*
* <p>The name of the enum item is the name of the material, without the color part.</p>
*
* @see ItemUtils#colorize(ColorableMaterial, DyeColor) Compute a {@link Material} from a {@link ColorableMaterial}
* and a {@link DyeColor}.
* @see ItemUtils#colorize(ColorableMaterial, ChatColor) Compute a {@link Material} from a {@link ColorableMaterial}
* and a {@link ChatColor}.
*/
public enum ColorableMaterial {
BANNER,
BED,
CARPET,
CONCRETE,
CONCRETE_POWDER,
DYE,
GLAZED_TERRACOTTA,
SHULKER_BOX,
STAINED_GLASS,
STAINED_GLASS_PANE,
TERRACOTTA,
WALL_BANNER,
WOOL
}
111 changes: 103 additions & 8 deletions src/main/java/fr/zcraft/quartzlib/tools/items/ItemUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import org.bukkit.ChatColor;
import org.bukkit.DyeColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
Expand All @@ -47,6 +50,9 @@
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.Potion;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

//import org.bukkit.Sound;

Expand Down Expand Up @@ -103,7 +109,7 @@ public static ItemStack consumeItem(Player player, ItemStack item) {
* @param player The player to give the item to.
* @param item The item to give to the player
* @return true if the player received the item in its inventory, false if
* it had to be totally or partially dropped on the ground.
* it had to be totally or partially dropped on the ground.
*/
public static boolean give(final Player player, final ItemStack item) {
final Map<Integer, ItemStack> leftover = player.getInventory().addItem(item);
Expand Down Expand Up @@ -152,8 +158,7 @@ public static boolean areSimilar(ItemStack first, ItemStack other) {
&& first.getData().equals(other.getData())
&& ((!first.hasItemMeta() && !other.hasItemMeta())
|| (!first.getItemMeta().hasDisplayName() && !other.getItemMeta().hasDisplayName())
|| (first.getItemMeta().getDisplayName().equals(other.getItemMeta().getDisplayName()))
);
|| (first.getItemMeta().getDisplayName().equals(other.getItemMeta().getDisplayName())));
}

/**
Expand Down Expand Up @@ -326,7 +331,7 @@ private static Method getRegistryLookupMethod() throws NMSException {
*
* @param item An item.
* @return The Minecraft name of this item, or null if the item's material
* is invalid.
* is invalid.
* @throws NMSException if the operation cannot be executed.
*/
public static String getMinecraftId(ItemStack item) throws NMSException {
Expand Down Expand Up @@ -407,8 +412,8 @@ public static Object asCraftCopy(ItemStack item) throws NMSException {
*
* @param item An item.
* @return A NMS ItemStack for this item. If the item was a CraftItemStack,
* this will be the item's handle directly; in the other cases, a copy in a
* NMS ItemStack object.
* this will be the item's handle directly; in the other cases, a copy in a
* NMS ItemStack object.
* @throws NMSException if the operation cannot be executed.
*/
public static Object getNMSItemStack(ItemStack item) throws NMSException {
Expand All @@ -427,8 +432,8 @@ public static Object getNMSItemStack(ItemStack item) throws NMSException {
*
* @param item An item.
* @return A CraftItemStack for this item. If the item was initially a
* CraftItemStack, it is returned directly. In the other cases, a copy in a
* new CraftItemStack will be returned.
* CraftItemStack, it is returned directly. In the other cases,
* a copy in a new CraftItemStack will be returned.
* @throws NMSException if the operation cannot be executed.
*/
public static Object getCraftItemStack(ItemStack item) throws NMSException {
Expand Down Expand Up @@ -517,4 +522,94 @@ public static void dropLater(final Location location, final ItemStack item) {
RunTask.nextTick(() -> drop(location, item));
}

/**
* Converts a chat color to its dye equivalent.
*
* <p>The transformation is not perfect as there is no 1:1
* correspondence between dyes and chat colors.</p>
*
* @param color The chat color.
* @return The corresponding dye, or an empty value if none match (e.g. for formatting codes, of for {@code null}).
*/
@Contract(pure = true)
public static Optional<DyeColor> asDye(@Nullable final ChatColor color) {
if (color == null) {
return Optional.empty();
}

switch (color) {
case BLACK:
return Optional.of(DyeColor.BLACK);

case BLUE:
case DARK_BLUE:
return Optional.of(DyeColor.BLUE);

case DARK_GREEN:
return Optional.of(DyeColor.GREEN);

case DARK_AQUA:
return Optional.of(DyeColor.CYAN);

case DARK_RED:
return Optional.of(DyeColor.RED);

case DARK_PURPLE:
return Optional.of(DyeColor.PURPLE);

case GOLD:
case YELLOW:
return Optional.of(DyeColor.YELLOW);

case GRAY:
return Optional.of(DyeColor.LIGHT_GRAY);

case DARK_GRAY:
return Optional.of(DyeColor.GRAY);

case GREEN:
return Optional.of(DyeColor.LIME);

case AQUA:
return Optional.of(DyeColor.LIGHT_BLUE);

case RED:
return Optional.of(DyeColor.ORANGE);

case LIGHT_PURPLE:
return Optional.of(DyeColor.PINK);

case WHITE:
return Optional.of(DyeColor.WHITE);

// White, reset & formatting
default:
return Optional.empty();
}
}

/**
* Converts a dye color to a dyeable material.
*
* @param material The colorable material to colorize.
* @param color The dye color.
* @return The corresponding material.
*/
@Contract(pure = true)
public static Material colorize(@NotNull final ColorableMaterial material, @NotNull final DyeColor color) {
return Material.valueOf(color.name() + "_" + material.name());
}

/**
* Converts a chat color to a dyeable material.
*
* @param material The colorable material to colorize.
* @param color The chat color.
* @return The corresponding material. If the chat color was not convertible to a dye, {@code ChatColor#WHITE} is
* used.
*/
@Contract(pure = true)
public static Material colorize(@NotNull final ColorableMaterial material, @NotNull final ChatColor color) {
return colorize(material, asDye(color).orElse(DyeColor.WHITE));
}
}
109 changes: 109 additions & 0 deletions src/test/java/fr/zcraft/quartzlib/tools/items/ItemUtilsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright or © or Copr. QuartzLib contributors (2015 - 2020)
*
* This software is governed by the CeCILL-B license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL-B
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-B license and that you accept its terms.
*/

package fr.zcraft.quartzlib.tools.items;

import com.google.common.collect.ImmutableMap;
import fr.zcraft.quartzlib.MockedBukkitTest;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.bukkit.ChatColor;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.junit.Assert;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

@SuppressWarnings("checkstyle:linelength") // Justification: tests are much more readable with one per line
public class ItemUtilsTest extends MockedBukkitTest {

@Test
public void chatColorAreCorrectlyConvertedToDye() {
final Map<ChatColor, DyeColor> expectedConversion = ImmutableMap.<ChatColor, DyeColor>builder()
// All 16 colours are converted to their closest match
.put(ChatColor.BLACK, DyeColor.BLACK)
.put(ChatColor.BLUE, DyeColor.BLUE)
.put(ChatColor.DARK_BLUE, DyeColor.BLUE)
.put(ChatColor.GREEN, DyeColor.LIME)
.put(ChatColor.DARK_GREEN, DyeColor.GREEN)
.put(ChatColor.DARK_AQUA, DyeColor.CYAN)
.put(ChatColor.DARK_RED, DyeColor.RED)
.put(ChatColor.DARK_PURPLE, DyeColor.PURPLE)
.put(ChatColor.GOLD, DyeColor.YELLOW)
.put(ChatColor.YELLOW, DyeColor.YELLOW)
.put(ChatColor.GRAY, DyeColor.LIGHT_GRAY)
.put(ChatColor.DARK_GRAY, DyeColor.GRAY)
.put(ChatColor.AQUA, DyeColor.LIGHT_BLUE)
.put(ChatColor.RED, DyeColor.ORANGE)
.put(ChatColor.LIGHT_PURPLE, DyeColor.PINK)
.put(ChatColor.WHITE, DyeColor.WHITE)

.build();

final Set<DyeColor> dyes = new HashSet<>(expectedConversion.values());
Assert.assertEquals(
"All dye colors are matched against something except brown and magenta",
dyes.size(), DyeColor.values().length - 2
);

Arrays.stream(ChatColor.values()).forEach(chatColor -> {
final DyeColor dye = expectedConversion.get(chatColor);
Assert.assertEquals(
chatColor + " is correctly converted to" + (dye != null ? dye : "Optional.EMPTY"),
ItemUtils.asDye(chatColor),
dye != null ? Optional.of(dye) : Optional.empty()
);
});
}

@Test
public void blocksCanBeColorizedWithDyeColors() {
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.BANNER, DyeColor.BLUE), Material.BLUE_BANNER);
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.BED, DyeColor.LIME), Material.LIME_BED);
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.CARPET, DyeColor.GREEN), Material.GREEN_CARPET);
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.CONCRETE, DyeColor.BROWN), Material.BROWN_CONCRETE);
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.CONCRETE_POWDER, DyeColor.ORANGE), Material.ORANGE_CONCRETE_POWDER);
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.DYE, DyeColor.BLACK), Material.BLACK_DYE);
}

@Test
public void blocksCanBeColorizedWithChatColors() {
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.GLAZED_TERRACOTTA, ChatColor.AQUA), Material.LIGHT_BLUE_GLAZED_TERRACOTTA);
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.SHULKER_BOX, ChatColor.DARK_AQUA), Material.CYAN_SHULKER_BOX);
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.STAINED_GLASS, ChatColor.DARK_RED), Material.RED_STAINED_GLASS);
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.STAINED_GLASS_PANE, ChatColor.RED), Material.ORANGE_STAINED_GLASS_PANE);
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.TERRACOTTA, ChatColor.LIGHT_PURPLE), Material.PINK_TERRACOTTA);
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.WALL_BANNER, ChatColor.MAGIC), Material.WHITE_WALL_BANNER);
Assertions.assertEquals(ItemUtils.colorize(ColorableMaterial.WOOL, ChatColor.STRIKETHROUGH), Material.WHITE_WOOL);
}
}