Fixed Armor Upgrader only works after plugin reload

Fixed Chestplate is not automatically turned into dragon egg
Fixed non-armor uniques not removed on death
Fixed Other uniques not automatically redeemed
Fixed Abilities cooldown non-functional
This commit is contained in:
thetrouper
2025-04-02 22:57:51 -05:00
parent 991ce83369
commit 6e86143252
13 changed files with 187 additions and 48 deletions

View File

@@ -11,8 +11,4 @@
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -44,7 +44,8 @@ public enum Unique {
DRAGON_EGG(ItemBuilder.create()
.material(Material.NETHERITE_CHESTPLATE)
.lore(Text.legacyColor("&bAbilities:"))
.lore(Text.legacyColor("&3| &7Dragon's Breath"))
.lore(Text.legacyColor("&3| &7Bad Breath"))
.lore(Text.legacyColor(" &1- &7Shoot Dragon's Breath for 7 Seconds"))
.lore(Text.legacyColor("&3| &7Resistence I"))
.lore(Text.legacyColor("&3| &7Strength I"))
.enchant(Enchantment.BINDING_CURSE,1)
@@ -78,7 +79,8 @@ public enum Unique {
LEGGINGS(ItemBuilder.create()
.material(Material.NETHERITE_LEGGINGS)
.lore(Text.legacyColor("&bAbilities:"))
.lore(Text.legacyColor("&3| &7Knockback Shield"))
.lore(Text.legacyColor("&3| &7Back-Up"))
.lore(Text.legacyColor(" &1- &7Create a shield around you knocking players away"))
.lore(Text.legacyColor("&3| &7Resistence I"))
.enchant(Enchantment.BINDING_CURSE,1)
.enchant(Enchantment.PROTECTION,4)
@@ -90,8 +92,6 @@ public enum Unique {
"Netherite Leggings", (p) -> {
p.addPotionEffect(new PotionEffect(PotionEffectType.RESISTANCE,21,0,true,false,false));
}, (p) -> {
// TODO: Test Shield
Stream<Entity> toKnockBack = p.getNearbyEntities(10,10,10).stream().filter(target -> {
if (!(target instanceof Player v)) return false;
boolean tooClose = target.getLocation().distance(p.getLocation()) < 10;
@@ -140,6 +140,7 @@ public enum Unique {
.material(Material.NETHERITE_BOOTS)
.lore(Text.legacyColor("&bAbilities:"))
.lore(Text.legacyColor("&3| &7Dash"))
.lore(Text.legacyColor(" &1- &7Launch yourself forwards"))
.lore(Text.legacyColor("&3| &7Speed 1"))
.enchant(Enchantment.BINDING_CURSE,1)
.enchant(Enchantment.PROTECTION,4)
@@ -175,6 +176,9 @@ public enum Unique {
}, 50),
SWORD(ItemBuilder.create()
.material(Material.NETHERITE_SWORD)
.lore(Text.legacyColor("&bAbilities:"))
.lore(Text.legacyColor("&3| &7Go Wild"))
.lore(Text.legacyColor(" &1- &7Strength 2 for 7 seconds"))
.enchant(Enchantment.UNBREAKING,3)
.enchant(Enchantment.MENDING,1)
.enchant(Enchantment.SHARPNESS,5)
@@ -182,10 +186,13 @@ public enum Unique {
.build(),
"Netherite Sword", (p) -> {
}, (p) -> {
p.addPotionEffect(new PotionEffect(PotionEffectType.STRENGTH,140,1,true,false,false));
p.addPotionEffect(new PotionEffect(PotionEffectType.STRENGTH,20*7,1,true,false,false));
}, 50),
AXE(ItemBuilder.create()
.material(Material.NETHERITE_AXE)
.lore(Text.legacyColor("&bAbilities:"))
.lore(Text.legacyColor("&3| &7Rampage"))
.lore(Text.legacyColor(" &1- &7Haste 6 for 5 seconds"))
.enchant(Enchantment.UNBREAKING,3)
.enchant(Enchantment.MENDING,1)
.enchant(Enchantment.SHARPNESS,5)
@@ -194,7 +201,7 @@ public enum Unique {
.build(),
"Netherite Axe", (p) -> {
}, (p) -> {
p.addPotionEffect(new PotionEffect(PotionEffectType.HASTE,140,5,true,false,false));
p.addPotionEffect(new PotionEffect(PotionEffectType.HASTE,20*5,5,true,false,false));
}, 50);
private final ItemStack inGame;
@@ -217,10 +224,12 @@ public enum Unique {
public static boolean isUnique(ItemStack i) {
if (i == null) return false;
Verbose.send("Checking if item is unique %s",i.getType());
for (Unique value : values()) {
if (ItemUtils.isSimilar(value.getInGameItem(),i)) return true;
if (i.getType().equals(Material.DRAGON_EGG)) return true;
}
Verbose.send("Item did not match any unique material...");
return false;
}

View File

@@ -19,6 +19,7 @@ public class Manager {
public TierBackend tiers;
public Broadcaster broadcaster;
public UniquesBackend uniques;
public ArmorUpgrade upgrade;
public Manager() {
io = new IO();
@@ -33,7 +34,8 @@ public class Manager {
//uniques = new UniquesBackend();
broadcaster = new Broadcaster();
uniques = new UniquesBackend();
upgrade = new ArmorUpgrade();
registerCommands();
registerEvents();
registerCrafting();
@@ -66,9 +68,8 @@ public class Manager {
private void registerCrafting() {
ArmorSMP.getInstance().getLogger().info("Registering Crafts");
ArmorUpgrade armorUpgrade = new ArmorUpgrade();
armorUpgrade.removeRecipe();
armorUpgrade.addRecipe();
upgrade.removeRecipe();
upgrade.addRecipe();
}
}

View File

@@ -19,7 +19,7 @@ import java.util.UUID;
@CommandRegistry(value = "ability", printStackTrace = true, playersOnly = true)
public class AbilityCommand implements CustomCommand {
private final Cooldown<Pair<Unique, UUID>> abilityCooldown = new Cooldown<>();
private final Cooldown<String> abilityCooldown = new Cooldown<>();
@Override
public void dispatchCommand(CommandSender sender, Command command, String label, Args args) {
@@ -33,12 +33,12 @@ public class AbilityCommand implements CustomCommand {
Text.sendMessage(false, Text.Pallet.WARNING, sender, "You do not own the {0}.",piece.getCanonical());
return;
}
if (abilityCooldown.isOnCooldown(Pair.of(piece,p.getUniqueId()))) {
Text.sendMessage(false, Text.Pallet.WARNING, sender, "The ability for your {0} is on cooldown for {1} seconds.",piece.getCanonical(),abilityCooldown.getCooldownSec(Pair.of(piece,p.getUniqueId())));
if (abilityCooldown.isOnCooldown(getCooldownString(p.getUniqueId(),piece))) {
Text.sendMessage(false, Text.Pallet.WARNING, sender, "The ability for your {0} is on cooldown for {1} seconds.",piece.getCanonical(),abilityCooldown.getCooldownSec(getCooldownString(p.getUniqueId(),piece)));
return;
}
piece.getAbility().accept(p);
abilityCooldown.addCooldown(Pair.of(piece,p.getUniqueId()),piece.getAbilityCooldownSeconds() * 1000L);
abilityCooldown.addCooldown(getCooldownString(p.getUniqueId(),piece),piece.getAbilityCooldownSeconds() * 1000L);
Text.sendMessage(false, Text.Pallet.SUCCESS,sender,"Successfully used your {0}'s ability!",piece.getCanonical());
}
@@ -46,4 +46,8 @@ public class AbilityCommand implements CustomCommand {
public void dispatchCompletions(CommandSender commandSender, Command command, String label, CompletionBuilder b) {
b.then(b.argEnum(Unique.class));
}
public String getCooldownString(UUID who, Unique what) {
return "%s:%s".formatted(who,what);
}
}

View File

@@ -9,7 +9,6 @@ import me.trouper.armorsmp.ArmorSMP;
import me.trouper.armorsmp.data.ArmorTier;
import me.trouper.armorsmp.data.io.Config;
import me.trouper.armorsmp.data.Unique;
import me.trouper.armorsmp.server.crafting.ArmorUpgrade;
import me.trouper.armorsmp.utils.Text;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
@@ -51,9 +50,15 @@ public class AdminCommand implements CustomCommand {
b.arg("toggle")
)
.then(
b.arg("include","exclude")
b.arg("exclude")
.then(
b.arg("Class.method")))
.then(
b.arg("include")
.then(
b.arg(ArmorSMP.getInstance().getManager().io.config.debuggerExclusions)
)
)
).then(
b.arg("change")
.then(
@@ -181,7 +186,7 @@ public class AdminCommand implements CustomCommand {
return;
}
target.getInventory().addItem(ArmorUpgrade.ARMOR_UGPRADE);
target.getInventory().addItem(ArmorSMP.getInstance().getManager().upgrade.getItem());
Text.sendMessage(false, Text.Pallet.SUCCESS, sender, "Given and Upgrader to {0}", target.getName());
}

View File

@@ -2,23 +2,28 @@ package me.trouper.armorsmp.server.crafting;
import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
import me.trouper.armorsmp.ArmorSMP;
import me.trouper.armorsmp.utils.Text;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
public class ArmorUpgrade {
public static final ItemStack ARMOR_UGPRADE = ItemBuilder.create()
.material(Material.NETHER_STAR)
.name("§b§lArmor Upgrader")
.lore("§9| §3Right click to upgrade your gear")
.count(1)
.customModelData(1)
.build();
private ItemStack armorUpgrade;
public final NamespacedKey key;
public final ShapedRecipe recipe;
public static final NamespacedKey KEY = new NamespacedKey(ArmorSMP.getInstance(), "armor_upgrade_recipe");
public static ShapedRecipe recipe = new ShapedRecipe(KEY, ARMOR_UGPRADE);
public ArmorUpgrade() {
this.key = new NamespacedKey(ArmorSMP.getInstance(), "armor_upgrade_recipe");
this.armorUpgrade = ItemBuilder.create()
.material(Material.NETHER_STAR)
.name(Text.legacyColor("&b&lArmor Upgrade"))
.lore(Text.legacyColor("&9| &3Right click to upgrade your gear"))
.count(1)
.customModelData(1)
.build();
this.recipe = new ShapedRecipe(key, armorUpgrade);
}
public void addRecipe() {
recipe.shape("ABC", "DEF", "GHI");
@@ -39,6 +44,26 @@ public class ArmorUpgrade {
}
public void removeRecipe() {
ArmorSMP.getInstance().getServer().removeRecipe(KEY);
ArmorSMP.getInstance().getServer().removeRecipe(key);
}
public ItemStack getItem() {
if (!armorUpgrade.getType().equals(Material.NETHER_STAR)) {
armorUpgrade = ItemBuilder.create()
.material(Material.NETHER_STAR)
.name(Text.legacyColor("&b&lArmor Upgrade"))
.lore(Text.legacyColor("&9| &3Right click to upgrade your gear"))
.count(1)
.customModelData(1)
.build();
return ItemBuilder.create()
.material(Material.NETHER_STAR)
.name(Text.legacyColor("&b&lArmor Upgrade"))
.lore(Text.legacyColor("&9| &3Right click to upgrade your gear"))
.count(1)
.customModelData(1)
.build();
}
return armorUpgrade;
}
}

View File

@@ -3,15 +3,17 @@ package me.trouper.armorsmp.server.events;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.armorsmp.ArmorSMP;
import me.trouper.armorsmp.data.ArmorTier;
import me.trouper.armorsmp.server.crafting.ArmorUpgrade;
import me.trouper.armorsmp.data.Unique;
import me.trouper.armorsmp.utils.Text;
import me.trouper.armorsmp.utils.Verbose;
import me.trouper.armorsmp.utils.ItemUtils;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.inventory.ItemStack;
public class DeathEvents implements CustomListener {
@@ -21,6 +23,9 @@ public class DeathEvents implements CustomListener {
final ArmorTier tier = ArmorSMP.getInstance().getManager().tiers.getTier(p);
Verbose.send("Handling death event for %s, their tier is %s",p.getName(),tier);
e.getDrops().removeIf(ItemUtils::notDroppable);
if (ArmorSMP.getInstance().getManager().uniques.isOwner(p,Unique.DRAGON_EGG)) {
e.getDrops().add(new ItemStack(Material.DRAGON_EGG));
}
if (tier.equals(ArmorTier.NONE)) {
Verbose.send("Tier was none");
@@ -29,7 +34,7 @@ public class DeathEvents implements CustomListener {
}
if (ArmorSMP.getInstance().getManager().tiers.downTier(p)) {
Verbose.send("They have been down-tiered");
e.getDrops().add(ArmorUpgrade.ARMOR_UGPRADE);
e.getDrops().add(ArmorSMP.getInstance().getManager().upgrade.getItem());
e.deathMessage(Text.getMessage(false, Text.Pallet.INFO,"{0} has died, and dropped an {1}!", LegacyComponentSerializer.legacyAmpersand().serialize(p.name()),"Armor Upgrader"));
}
ArmorSMP.getInstance().getManager().uniques.dropAllUniques(p);
@@ -38,5 +43,6 @@ public class DeathEvents implements CustomListener {
@EventHandler
public void onRespawn(PlayerRespawnEvent e) {
ArmorSMP.getInstance().getManager().tiers.queueUpdate(e.getPlayer(),false);
ArmorSMP.getInstance().getManager().uniques.queueUpdate(e.getPlayer());
}
}

View File

@@ -3,7 +3,7 @@ package me.trouper.armorsmp.server.events;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.armorsmp.ArmorSMP;
import me.trouper.armorsmp.data.ArmorTier;
import me.trouper.armorsmp.server.crafting.ArmorUpgrade;
import me.trouper.armorsmp.utils.ItemUtils;
import me.trouper.armorsmp.utils.Text;
import me.trouper.armorsmp.utils.Verbose;
import org.bukkit.entity.Player;
@@ -15,21 +15,24 @@ public class UpgradeRedeemEvent implements CustomListener {
@EventHandler
public void onClick(PlayerInteractEvent e) {
Verbose.send("Detected player clicking.");
Player p = e.getPlayer();
ItemStack holding = e.getItem();
ItemStack holding = e.getPlayer().getInventory().getItemInMainHand();
if (holding == null || holding.isEmpty()) return;
Verbose.send("Detected Interact Event Holding: %s", holding.getType());
if (!holding.getType().equals(ArmorUpgrade.ARMOR_UGPRADE.getType())) return;
if (!holding.hasItemMeta()) return;
if (holding.getItemMeta().getCustomModelData() != ArmorUpgrade.ARMOR_UGPRADE.getItemMeta().getCustomModelData()) return;
if (holding.isEmpty()) return;
if (!ItemUtils.isSimilar(holding,ArmorSMP.getInstance().getManager().upgrade.getItem())) {
Verbose.send("Player was not holding an Armor Upgrader");
return;
}
final ArmorTier tier = ArmorSMP.getInstance().getManager().tiers.getTier(p);
if (ArmorSMP.getInstance().getManager().tiers.upTier(p)) {
holding.setAmount(holding.getAmount() - 1);
holding.setAmount(holding.getAmount() - 1);
Verbose.send("Successfully updated player");
Text.sendMessage(true, Text.Pallet.INFO,p,"Successfully redeemed armor upgrade! Tier {0} -> Tier {1}",tier,ArmorSMP.getInstance().getManager().tiers.getTier(p));
} else {
Verbose.send("Failed to update player (tier manager refused)");
Text.sendMessage(true, Text.Pallet.ERROR,p,"Unable to upgrade. You are already at the maximum Armor Tier!");
}
}

View File

@@ -1,22 +1,37 @@
package me.trouper.armorsmp.utils;
import com.google.common.collect.Multimap;
import me.trouper.armorsmp.data.Unique;
import org.bukkit.Material;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class ItemUtils {
public static boolean notDroppable(ItemStack i) {
return isArmor(i) && !isUnique(i) && !isDragonEggEquivalent(i);
boolean armor = isArmor(i);
boolean unique = isUnique(i);
boolean isEgg = isDragonEggEquivalent(i);
Verbose.send("""
Item Type: %s
Unique: %b
Armor: %b
Egg Equivalent: %b
And: %b
""",i.getType().name(),unique,armor,isEgg,(!unique && armor));
return (!unique && armor) || isEgg;
}
private static boolean isDragonEggEquivalent(ItemStack i) {
Material m = i.getType();
return m.equals(Unique.DRAGON_EGG);
return m.equals(Unique.DRAGON_EGG.getInGameItem().getType());
}
public static boolean isArmor(ItemStack i) {
@@ -62,16 +77,91 @@ public class ItemUtils {
}
public static boolean isSimilar(ItemStack item1, ItemStack item2) {
if (item1 == null || item2 == null) return false;
if (item1.getType() != item2.getType()) return false;
if (item1.hasItemMeta() != item2.hasItemMeta()) return false;
if (item1 == null || item2 == null) {
Verbose.send("One of the items is null: item1: %s, item2: %s", item1, item2);
return false;
}
// Check material/type
Material type1 = item1.getType();
Material type2 = item2.getType();
boolean typeEqual = type1 == type2;
Verbose.send("Checking Material: item1 type: %s, item2 type: %s, equal: %s", type1, type2, typeEqual);
if (!typeEqual) return false;
// Check existence of ItemMeta
boolean hasMeta1 = item1.hasItemMeta();
boolean hasMeta2 = item2.hasItemMeta();
boolean metaExistEqual = (hasMeta1 == hasMeta2);
Verbose.send("Checking ItemMeta existence: item1 has meta: %s, item2 has meta: %s, equal: %s", hasMeta1, hasMeta2, metaExistEqual);
if (!metaExistEqual) return false;
// If neither item has meta, they are similar (nothing else to compare)
if (!hasMeta1 && !hasMeta2) {
return true;
}
// Both items have meta
ItemMeta meta1 = item1.getItemMeta();
ItemMeta meta2 = item2.getItemMeta();
return meta1 == null || meta2 == null || meta1.equals(meta2);
// Custom Name Check with null handling
String name1 = meta1.hasDisplayName() ? meta1.getDisplayName() : null;
String name2 = meta2.hasDisplayName() ? meta2.getDisplayName() : null;
if (name1 == null ^ name2 == null) { // one is null and the other is not
Verbose.send("Custom Name mismatch: item1 name: %s, item2 name: %s", name1, name2);
return false;
}
boolean nameEqual = (name1 == null || name1.equals(name2));
Verbose.send("Checking Custom Name: item1: %s, item2: %s, equal: %s", name1, name2, nameEqual);
if (!nameEqual) return false;
// Lore Check with null handling
List<String> lore1 = meta1.hasLore() ? meta1.getLore() : null;
List<String> lore2 = meta2.hasLore() ? meta2.getLore() : null;
if (lore1 == null ^ lore2 == null) {
Verbose.send("Lore mismatch: item1 lore: %s, item2 lore: %s", lore1, lore2);
return false;
}
boolean loreEqual = (lore1 == null || lore1.equals(lore2));
Verbose.send("Checking Lore: item1: %s, item2: %s, equal: %s", lore1, lore2, loreEqual);
if (!loreEqual) return false;
// Custom Model Data Check: Using -1 as the default if not set
int cmd1 = meta1.hasCustomModelData() ? meta1.getCustomModelData() : -1;
int cmd2 = meta2.hasCustomModelData() ? meta2.getCustomModelData() : -1;
boolean cmdEqual = (cmd1 == cmd2);
Verbose.send("Checking Custom Model Data: item1: %d, item2: %d, equal: %s", cmd1, cmd2, cmdEqual);
if (!cmdEqual) return false;
// Enchantments Check with null handling (should not be null by API, but checking for safety)
Map<Enchantment, Integer> enchants1 = meta1.getEnchants();
Map<Enchantment, Integer> enchants2 = meta2.getEnchants();
if (enchants1 == null ^ enchants2 == null) {
Verbose.send("Enchantments mismatch: item1 enchants: %s, item2 enchants: %s", enchants1, enchants2);
return false;
}
boolean enchantsEqual = (enchants1 == null || enchants1.equals(enchants2));
Verbose.send("Checking Enchantments: item1: %s, item2: %s, equal: %s", enchants1, enchants2, enchantsEqual);
if (!enchantsEqual) return false;
// Attribute Modifiers Check with null handling
Multimap<Attribute, AttributeModifier> modifiers1 = meta1.getAttributeModifiers();
Multimap<Attribute, AttributeModifier> modifiers2 = meta2.getAttributeModifiers();
if (modifiers1 == null ^ modifiers2 == null) {
Verbose.send("Attribute Modifiers mismatch: item1 modifiers: %s, item2 modifiers: %s", modifiers1, modifiers2);
return false;
}
boolean modifiersEqual = (modifiers1 == null || modifiers1.equals(modifiers2));
Verbose.send("Checking Attribute Modifiers: item1: %s, item2: %s, equal: %s", modifiers1, modifiers2, modifiersEqual);
if (!modifiersEqual) return false;
// All checks passed
return true;
}
/** @excludes unique enchants */
public static void transferEnchants(ItemStack oldItem, ItemStack newItem) {
if (oldItem != null && !isUnique(oldItem)) {