1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-19 19:25:48 +00:00

Merge pull request #3117 from martinbrom/chore/limited-use-item

Add LimitedUseItem - base class for items with limited uses
This commit is contained in:
TheBusyBiscuit 2021-07-17 18:54:16 +02:00 committed by GitHub
commit 53413747f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 187 additions and 83 deletions

View File

@ -570,7 +570,7 @@ public final class SlimefunItems {
public static final SlimefunItemStack STAFF_WIND = new SlimefunItemStack("STAFF_ELEMENTAL_WIND", Material.STICK, "&6Elemental Staff &7- &b&oWind", "", "&7Element: &b&oWind", "", "&eRight Click&7 to launch yourself forward");
public static final SlimefunItemStack STAFF_FIRE = new SlimefunItemStack("STAFF_ELEMENTAL_FIRE", Material.STICK, "&6Elemental Staff &7- &c&oFire", "", "&7Element: &c&oFire");
public static final SlimefunItemStack STAFF_WATER = new SlimefunItemStack("STAFF_ELEMENTAL_WATER", Material.STICK, "&6Elemental Staff &7- &1&oWater", "", "&7Element: &1&oWater", "", "&eRight Click&7 to extinguish yourself");
public static final SlimefunItemStack STAFF_STORM = new SlimefunItemStack("STAFF_ELEMENTAL_STORM", Material.STICK, "&6Elemental Staff &7- &8&oStorm", "", "&7Element: &8&oStorm", "", "&eRight Click&7 to summon a lightning", "&e" + StormStaff.MAX_USES + " Uses &7left");
public static final SlimefunItemStack STAFF_STORM = new SlimefunItemStack("STAFF_ELEMENTAL_STORM", Material.STICK, "&6Elemental Staff &7- &8&oStorm", "", "&7Element: &8&oStorm", "", "&eRight Click&7 to summon a lightning", LoreBuilder.usesLeft(StormStaff.MAX_USES));
static {
STAFF_WIND.addUnsafeEnchantment(Enchantment.LUCK, 1);

View File

@ -0,0 +1,149 @@
package io.github.thebusybiscuit.slimefun4.implementation.items;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves.StormStaff;
import io.github.thebusybiscuit.slimefun4.utils.LoreBuilder;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* This class represents an item with a limited number of uses.
* When the item runs out of "uses", it breaks.
*
* @author Linox
* @author Walshy
* @author TheBusyBiscuit
* @author martinbrom
*
* @see StormStaff
*/
public abstract class LimitedUseItem extends SimpleSlimefunItem<ItemUseHandler> {
private final NamespacedKey defaultUsageKey = new NamespacedKey(SlimefunPlugin.instance(), "uses_left");
private int maxUseCount = -1;
@ParametersAreNonnullByDefault
public LimitedUseItem(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
addItemHandler(getItemHandler());
}
/**
* Returns the number of times this item can be used.
*
* @return The number of times this item can be used.
*/
public final int getMaxUseCount() {
return maxUseCount;
}
/**
* Sets the maximum number of times this item can be used.
* The number must be greater than zero.
*
* @param count The maximum number of times this item can be used.
* @return The {@link LimitedUseItem} for chaining of setters
*/
public final @Nonnull LimitedUseItem setMaxUseCount(int count) {
Validate.isTrue(count > 0, "The maximum use count must be greater than zero!");
maxUseCount = count;
return this;
}
/**
* Returns the {@link NamespacedKey} under which will the amount of uses left stored.
*
* @return The {@link NamespacedKey} to store/load the amount of uses
*/
protected @Nonnull NamespacedKey getStorageKey() {
return defaultUsageKey;
}
@Override
public void register(@Nonnull SlimefunAddon addon) {
if (getMaxUseCount() < 1) {
warn("The use count has not been configured correctly. It needs to be at least 1. The Item was disabled.");
} else {
super.register(addon);
}
}
@ParametersAreNonnullByDefault
protected void damageItem(Player p, ItemStack item) {
if (item.getAmount() > 1) {
item.setAmount(item.getAmount() - 1);
// Separate one item from the stack and damage it
ItemStack separateItem = item.clone();
separateItem.setAmount(1);
damageItem(p, separateItem);
// Try to give the Player the new item
if (!p.getInventory().addItem(separateItem).isEmpty()) {
// or throw it on the ground
p.getWorld().dropItemNaturally(p.getLocation(), separateItem);
}
} else {
ItemMeta meta = item.getItemMeta();
NamespacedKey key = getStorageKey();
PersistentDataContainer pdc = meta.getPersistentDataContainer();
int usesLeft = pdc.getOrDefault(key, PersistentDataType.INTEGER, getMaxUseCount());
if (usesLeft == 1) {
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
item.setAmount(0);
item.setType(Material.AIR);
} else {
usesLeft--;
pdc.set(key, PersistentDataType.INTEGER, usesLeft);
updateItemLore(item, meta, usesLeft);
}
}
}
@ParametersAreNonnullByDefault
private void updateItemLore(ItemStack item, ItemMeta meta, int usesLeft) {
List<String> lore = meta.getLore();
String newLine = ChatColors.color(LoreBuilder.usesLeft(usesLeft));
if (lore != null && !lore.isEmpty()) {
// find the correct line
for (int i = 0; i < lore.size(); i++) {
if (PatternUtils.USES_LEFT_LORE.matcher(lore.get(i)).matches()) {
lore.set(i, newLine);
meta.setLore(lore);
item.setItemMeta(meta);
return;
}
}
} else {
meta.setLore(Collections.singletonList(newLine));
item.setItemMeta(meta);
}
}
}

View File

@ -1,7 +1,5 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
@ -10,20 +8,16 @@ import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.entity.LightningStrike;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.LimitedUseItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@ -32,37 +26,31 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* This {@link SlimefunItem} casts a {@link LightningStrike} where you are pointing.
* Unlike the other Staves, it has a limited amount of uses.
*
*
* @author Linox
* @author Walshy
* @author TheBusyBiscuit
*
*/
public class StormStaff extends SimpleSlimefunItem<ItemUseHandler> {
public class StormStaff extends LimitedUseItem {
private static final NamespacedKey usageKey = new NamespacedKey(SlimefunPlugin.instance(), "stormstaff_usage");
public static final int MAX_USES = 8;
private final NamespacedKey usageKey = new NamespacedKey(SlimefunPlugin.instance(), "stormstaff_usage");
@ParametersAreNonnullByDefault
public StormStaff(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe, getCraftedOutput());
}
super(category, item, recipeType, recipe);
@Nonnull
private static ItemStack getCraftedOutput() {
ItemStack item = SlimefunItems.STAFF_STORM.clone();
ItemMeta im = item.getItemMeta();
List<String> lore = im.getLore();
lore.set(4, ChatColors.color("&e" + MAX_USES + " Uses &7left"));
im.setLore(lore);
item.setItemMeta(im);
return item;
setMaxUseCount(MAX_USES);
}
@Override
public ItemUseHandler getItemHandler() {
protected @Nonnull NamespacedKey getStorageKey() {
return usageKey;
}
@Override
public @Nonnull ItemUseHandler getItemHandler() {
return e -> {
Player p = e.getPlayer();
ItemStack item = e.getItem();
@ -87,7 +75,10 @@ public class StormStaff extends SimpleSlimefunItem<ItemUseHandler> {
@ParametersAreNonnullByDefault
private void useItem(Player p, ItemStack item, Location loc) {
loc.getWorld().strikeLightning(loc);
World world = loc.getWorld();
if (world != null) {
world.strikeLightning(loc);
}
if (item.getType() == Material.SHEARS) {
return;
@ -105,39 +96,4 @@ public class StormStaff extends SimpleSlimefunItem<ItemUseHandler> {
damageItem(p, item);
}
@ParametersAreNonnullByDefault
private void damageItem(Player p, ItemStack item) {
if (item.getAmount() > 1) {
item.setAmount(item.getAmount() - 1);
// Seperate one item from the stack and damage it
ItemStack seperateItem = item.clone();
seperateItem.setAmount(1);
damageItem(p, seperateItem);
// Try to give the Player the new item
if (!p.getInventory().addItem(seperateItem).isEmpty()) {
// or throw it on the ground
p.getWorld().dropItemNaturally(p.getLocation(), seperateItem);
}
} else {
ItemMeta meta = item.getItemMeta();
int usesLeft = meta.getPersistentDataContainer().getOrDefault(usageKey, PersistentDataType.INTEGER, MAX_USES);
if (usesLeft == 1) {
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
item.setAmount(0);
} else {
usesLeft--;
meta.getPersistentDataContainer().set(usageKey, PersistentDataType.INTEGER, usesLeft);
List<String> lore = meta.getLore();
lore.set(4, ChatColors.color("&e" + usesLeft + ' ' + (usesLeft > 1 ? "Uses" : "Use") + " &7left"));
meta.setLore(lore);
item.setItemMeta(meta);
}
}
}
}

View File

@ -33,54 +33,48 @@ public final class LoreBuilder {
private LoreBuilder() {}
@Nonnull
public static String radioactive(@Nonnull Radioactivity radioactivity) {
public static @Nonnull String radioactive(@Nonnull Radioactivity radioactivity) {
return radioactivity.getLore();
}
@Nonnull
public static String machine(@Nonnull MachineTier tier, @Nonnull MachineType type) {
public static @Nonnull String machine(@Nonnull MachineTier tier, @Nonnull MachineType type) {
return tier + " " + type;
}
@Nonnull
public static String speed(float speed) {
public static @Nonnull String speed(float speed) {
return "&8\u21E8 &b\u26A1 &7Speed: &b" + speed + 'x';
}
@Nonnull
public static String powerBuffer(int power) {
public static @Nonnull String powerBuffer(int power) {
return power(power, " Buffer");
}
@Nonnull
public static String powerPerSecond(int power) {
public static @Nonnull String powerPerSecond(int power) {
return power(power, "/s");
}
@Nonnull
public static String power(int power, @Nonnull String suffix) {
public static @Nonnull String power(int power, @Nonnull String suffix) {
return "&8\u21E8 &e\u26A1 &7" + power + " J" + suffix;
}
@Nonnull
public static String powerCharged(int charge, int capacity) {
public static @Nonnull String powerCharged(int charge, int capacity) {
return "&8\u21E8 &e\u26A1 &7" + charge + " / " + capacity + " J";
}
@Nonnull
public static String material(@Nonnull String material) {
public static @Nonnull String material(@Nonnull String material) {
return "&8\u21E8 &7Material: &b" + material;
}
@Nonnull
public static String hunger(double value) {
public static @Nonnull String hunger(double value) {
return "&7&oRestores &b&o" + hungerFormat.format(value) + " &7&oHunger";
}
@Nonnull
public static String range(int blocks) {
public static @Nonnull String range(int blocks) {
return "&7Range: &c" + blocks + " blocks";
}
public static @Nonnull String usesLeft(int usesLeft) {
return "&e" + usesLeft + ' ' + (usesLeft > 1 ? "Uses" : "Use") + " &7left";
}
}

View File

@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.utils;
import java.util.regex.Pattern;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
/**
* This class is created for common-use patterns used in things such as {@link String#split(String)}. <br>
* Every time something like {@link String#split(String)} is called it will compile a {@link Pattern},
@ -32,4 +34,7 @@ public final class PatternUtils {
public static final Pattern MINECRAFT_MATERIAL = Pattern.compile("minecraft:[a-z_]+");
public static final Pattern MINECRAFT_TAG = Pattern.compile("#minecraft:[a-z_]+");
public static final Pattern SLIMEFUN_TAG = Pattern.compile("#slimefun:[a-z_]+");
public static final Pattern USES_LEFT_LORE = Pattern.compile(ChatColors.color("&e[0-9]+ Uses? &7left"));
}