Made shield look cool

This commit is contained in:
2025-03-28 19:26:01 -05:00
parent 3584129709
commit 44972f8465
17 changed files with 215 additions and 52 deletions

View File

@@ -1,25 +1,24 @@
package me.trouper.armorsmp.data;
import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
import io.github.itzispyder.pdk.utils.misc.SoundPlayer;
import io.github.itzispyder.pdk.utils.raytracers.CustomDisplayRaytracer;
import me.trouper.armorsmp.ArmorSMP;
import me.trouper.armorsmp.utils.Display;
import me.trouper.armorsmp.utils.Text;
import me.trouper.armorsmp.utils.Verbose;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.World;
import org.bukkit.block.Block;
import me.trouper.armorsmp.utils.WorldUtils;
import org.bukkit.*;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.*;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.stream.Stream;
@@ -38,8 +37,8 @@ public enum Unique {
.customModelData(2)
.build(),
"Netherite Helmet", (p) -> {
p.addPotionEffect(new PotionEffect(PotionEffectType.FIRE_RESISTANCE,21,1,true,false,false));
p.addPotionEffect(new PotionEffect(PotionEffectType.HEALTH_BOOST,25,3,true,false,false));
p.addPotionEffect(new PotionEffect(PotionEffectType.FIRE_RESISTANCE,21,0,true,false,false));
p.addPotionEffect(new PotionEffect(PotionEffectType.HEALTH_BOOST,25,2,true,false,false));
}, (p) -> {
}, 50),
CHESTPLATE(ItemBuilder.create()
@@ -58,7 +57,6 @@ public enum Unique {
p.addPotionEffect(new PotionEffect(PotionEffectType.STRENGTH,21,0,true,false,false));
p.addPotionEffect(new PotionEffect(PotionEffectType.RESISTANCE,21,0,true,false,false));
}, (p) -> {
// TODO: Test Dragon's Breath
World world = p.getWorld();
Location eyeLocation = p.getEyeLocation();
@@ -76,7 +74,6 @@ public enum Unique {
cloud.setParticle(Particle.DRAGON_BREATH);
cloud.addCustomEffect(PotionEffectType.INSTANT_DAMAGE.createEffect(1,1),true);
cloud.setOwnerUniqueId(p.getUniqueId());
}, 50),
LEGGINGS(ItemBuilder.create()
.material(Material.NETHERITE_LEGGINGS)
@@ -94,6 +91,7 @@ public enum Unique {
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;
@@ -109,6 +107,34 @@ public enum Unique {
target.setVelocity(direction);
}));
AtomicBoolean cancelShield = new AtomicBoolean();
Bukkit.getScheduler().runTaskLater(ArmorSMP.getInstance(),(task)->{
cancelShield.set(true);
},120);
Bukkit.getScheduler().runTaskTimer(ArmorSMP.getInstance(), (task) -> {
if (cancelShield.get()) task.cancel();
World w = p.getWorld();
Particle.DustOptions dust = new Particle.DustOptions(Color.AQUA, 0.5F);
Display.sphere(p.getEyeLocation(), 5.0, 0.5, 0.5, point -> {
w.spawnParticle(Particle.DUST, point, 1, 0, 0, 0, 0, dust);
});
List<Entity> targets = new ArrayList<>(w.getNearbyEntities(p.getLocation(), 10, 10, 10, entity ->
entity instanceof LivingEntity living && !living.isDead() && living != p && living.getLocation().distance(p.getLocation()) < 5
));
targets.forEach(target -> {
if (target instanceof LivingEntity living) {
SoundPlayer blockSound = new SoundPlayer(target.getLocation(), Sound.ITEM_SHIELD_BLOCK, 1, 1);
Vector direction = target.getLocation().toVector().subtract(p.getEyeLocation().toVector()).normalize();
double strength = 2.0;
double verticalMultiplier = 0.5;
living.setVelocity(direction.multiply(strength).setY(verticalMultiplier));
blockSound.playWithin(10);
w.spawnParticle(Particle.POOF,target.getLocation().clone().add(0,1,0),10,0.2,1,0.2,0.1);
}
});
}, 0,2);
}, 45),
BOOTS(ItemBuilder.create()
.material(Material.NETHERITE_BOOTS)
@@ -175,14 +201,14 @@ public enum Unique {
private final String canonical;
private final Consumer<Player> passiveAbility;
private final Consumer<Player> ability;
private final int abilityCooldownTicks;
private final int abilityCooldownSeconds;
Unique(ItemStack inGame, String canonical, Consumer<Player> passiveAbility, Consumer<Player> ability, int abilityCooldownTicks) {
Unique(ItemStack inGame, String canonical, Consumer<Player> passiveAbility, Consumer<Player> ability, int abilityCooldownSeconds) {
this.inGame = inGame;
this.canonical = canonical;
this.passiveAbility = passiveAbility;
this.ability = ability;
this.abilityCooldownTicks = abilityCooldownTicks;
this.abilityCooldownSeconds = abilityCooldownSeconds;
}
public ItemStack getInGameItem() {
@@ -191,7 +217,7 @@ public enum Unique {
public static boolean isUnique(ItemStack i) {
for (Unique value : values()) {
if (value.getInGameItem().isSimilar(i)) return true;
if (WorldUtils.isSimilar(value.getInGameItem(),i)) return true;
if (i.getType().equals(Material.DRAGON_EGG)) return true;
}
return false;
@@ -201,7 +227,7 @@ public enum Unique {
Verbose.send("Matching Unique, Item Type: %s",i.getType());
Unique match = null;
for (Unique value : values()) {
if (value.getInGameItem().isSimilar(i)) {
if (WorldUtils.isSimilar(value.getInGameItem(),i)) {
match = value;
Verbose.send("Matched with, Unique: %s",match);
}
@@ -225,7 +251,7 @@ public enum Unique {
return passiveAbility;
}
public int getAbilityCooldownTicks() {
return abilityCooldownTicks;
public int getAbilityCooldownSeconds() {
return abilityCooldownSeconds;
}
}

View File

@@ -5,12 +5,14 @@ import me.trouper.armorsmp.ArmorSMP;
import me.trouper.armorsmp.utils.Verbose;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Config implements JsonSerializable<Config> {
public boolean debugMode = false;
public List<String> debuggerExclusions = new ArrayList<>();
@Override
public File getFile() {

View File

@@ -14,7 +14,6 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;
@CommandRegistry(value = "ability", printStackTrace = true, playersOnly = true)
@@ -39,7 +38,7 @@ public class AbilityCommand implements CustomCommand {
return;
}
piece.getAbility().accept(p);
abilityCooldown.addCooldown(Pair.of(piece,p.getUniqueId()),piece.getAbilityCooldownTicks() * 50L);
abilityCooldown.addCooldown(Pair.of(piece,p.getUniqueId()),piece.getAbilityCooldownSeconds() * 1000L);
Text.sendMessage(false, Text.Pallet.SUCCESS,sender,"Successfully used your {0}'s ability!",piece.getCanonical());
}

View File

@@ -11,6 +11,7 @@ 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 me.trouper.armorsmp.utils.Verbose;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
@@ -30,6 +31,7 @@ public class AdminCommand implements CustomCommand {
}
String sub = args.get(0).toString();
switch (sub) {
case "debug" -> handleDebug(sender,args);
case "reload" -> handleReload(sender,args);
case "change" -> handleChange(sender, args);
case "give" -> handleGive(sender, args);
@@ -43,25 +45,89 @@ public class AdminCommand implements CustomCommand {
@Override
public void dispatchCompletions(CommandSender commandSender, Command command, String label, CompletionBuilder b) {
b.then(
b.arg("reload")
).then(
b.arg("debug")
.then(
b.arg("toggle")
)
.then(
b.arg("include","exclude")
.then(
b.arg("Class.method")))
).then(
b.arg("change")
.then(b.argEnum(ArmorTier.class).then(b.argOnlinePlayers()))
.then(
b.argEnum(ArmorTier.class).then(
b.argOnlinePlayers()))
).then(
b.arg("give")
.then(b.arg("upgrader")
.then(b.argOnlinePlayers()))
.then(
b.arg("upgrader")
.then(
b.argOnlinePlayers()))
.then(b.arg("unique")
.then(b.argEnum(Unique.class)
.then(b.argOnlinePlayers())))
.then(
b.argEnum(Unique.class)
.then(
b.argOnlinePlayers())))
).then(
b.arg("reset")
.then(b.arg("mace"))
).then(
b.arg("remove")
.then(b.arg("unique")
.then(b.argEnum(Unique.class)
.then(b.argOnlinePlayers())))
).then(b.arg("toggle")
.then(b.arg("end","nether","mace","debug")));
.then(
b.arg("unique")
.then(
b.argEnum(Unique.class)
.then(
b.argOnlinePlayers())))
).then(
b.arg("toggle")
.then(
b.arg("end","nether","mace")));
}
private void handleDebug(CommandSender sender, Args args) {
if (args.getSize() < 2) {
Text.sendError(sender, "Usage: /armorsmp debug <toggle|include|exclude>");
return;
}
final String sub = args.get(1).toString();
Config config = ArmorSMP.getInstance().getManager().io.config;
switch (sub) {
case "toggle" -> {
boolean result = false;
config.debugMode = result = !config.debugMode;
config.save();
Text.sendMessage(false, Text.Pallet.SUCCESS,sender,"Toggled debug mode {0}.",result ? "on" : "off");
}
case "exclude" -> {
if (args.getSize() < 3) {
Text.sendError(sender, "Usage: /armorsmp debug exclude <method>");
return;
}
final String exclusion = args.get(2).toString();
config.debuggerExclusions.add(exclusion);
config.save();
Text.sendMessage(false, Text.Pallet.SUCCESS, sender, "Excluded {0} from the debugger.", exclusion);
}
case "include" -> {
if (args.getSize() < 3) {
Text.sendError(sender, "Usage: /armorsmp debug include <method>");
return;
}
final String exclusion = args.get(2).toString();
config.debuggerExclusions.remove(exclusion);
config.save();
Text.sendMessage(false, Text.Pallet.SUCCESS, sender, "Removed exclusion for {0} on the debugger.", exclusion);
}
}
}
private void handleReload(CommandSender sender, Args args) {
@@ -170,11 +236,6 @@ public class AdminCommand implements CustomCommand {
config.save();
feature = "Mace Crafting";
}
case "debug" -> {
config.debugMode = result = !config.debugMode;
config.save();
feature = "Debug Mode";
}
default -> {
Text.sendMessage(false, Text.Pallet.ERROR, sender, "Error: {0} is not a valid feature.", feature);
@@ -225,7 +286,7 @@ public class AdminCommand implements CustomCommand {
return;
}
ArmorSMP.getInstance().getManager().io.storage.uniques.owners.remove(piece);
ArmorSMP.getInstance().getManager().uniques.dropUnique(target,piece);
ArmorSMP.getInstance().getManager().armor.queueUpdate(target, true);
ArmorSMP.getInstance().getManager().uniques.queueUpdate(target);

View File

@@ -31,17 +31,22 @@ public class JoinEvent implements CustomListener {
private void handleUpdates(Player p) {
Verbose.send("Checking for updates needed on %s",p.getName());
final Map<String, Boolean> armorCache = ArmorSMP.getInstance().getManager().io.storage.armorUpdateCache;
final Set<String> uniquesCache = ArmorSMP.getInstance().getManager().io.storage.uniqueUpdateCache;
if (!ArmorSMP.getInstance().getManager().armor.verifyArmor(p)) {
Verbose.send("Updating armor");
ArmorSMP.getInstance().getManager().armor.queueUpdate(p,armorCache.getOrDefault(p.getUniqueId().toString(),true));
}
if (!ArmorSMP.getInstance().getManager().uniques.verifyUniques(p)) {
Verbose.send("Updating uniques");
ArmorSMP.getInstance().getManager().uniques.queueUpdate(p);
}
if (armorCache.containsKey(p.getUniqueId().toString())) {
Verbose.send("Updating armor from cache");
ArmorSMP.getInstance().getManager().armor.queueUpdate(p,armorCache.getOrDefault(p.getUniqueId().toString(),true));
ArmorSMP.getInstance().getManager().io.storage.armorUpdateCache.remove(p.getUniqueId().toString());
ArmorSMP.getInstance().getManager().io.storage.save();
}
final Set<String> uniquesCache = ArmorSMP.getInstance().getManager().io.storage.uniqueUpdateCache;
if (uniquesCache.contains(p.getUniqueId().toString())) {
Verbose.send("Updating uniques");
ArmorSMP.getInstance().getManager().uniques.queueUpdate(p);

View File

@@ -182,7 +182,6 @@ public class ArmorBackend {
|| unique.equals(Unique.BOOTS)
) {
storage.uniques.owners.remove(unique);
//target.getLocation().getWorld().dropItem(target.getLocation(),unique.getInGameItem());
}
if (unique.equals(Unique.CHESTPLATE)) {
target.getLocation().getWorld().dropItem(target.getLocation(),new ItemStack(Material.DRAGON_EGG));

View File

@@ -9,7 +9,10 @@ import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
public class UniquesBackend {
@@ -58,7 +61,7 @@ public class UniquesBackend {
public void dropUniqueItems(Player p) {
storage.uniques.owners.forEach((unique,owner)->{
if (unique.equals(Unique.MACE) || unique.equals(Unique.SWORD) || unique.equals(Unique.AXE) && owner.equals(p.getUniqueId().toString()) && !p.getInventory().contains(unique.getInGameItem())) {
if (unique.equals(Unique.MACE) || unique.equals(Unique.SWORD) || unique.equals(Unique.AXE) && owner.equals(p.getUniqueId().toString())) {
storage.uniques.owners.remove(unique);
}
});
@@ -66,9 +69,37 @@ public class UniquesBackend {
}
public void applyPersistence() {
Bukkit.getOnlinePlayers().forEach(this::applyEffects);
}
public void applyEffects(Player p) {
storage.uniques.owners.forEach((unique, owner) -> {
Player p = Bukkit.getPlayer(owner);
if (p != null && p.isOnline()) unique.getPassiveAbility().accept(p);
if (p != null && owner.equals(p.getUniqueId().toString()) && p.isOnline()) {
unique.getPassiveAbility().accept(p);
}
});
}
public boolean verifyUniques(Player p) {
AtomicBoolean success = new AtomicBoolean(false);
List<Boolean> checks = new ArrayList<>();
ArmorSMP.getInstance().getManager().io.storage.uniques.owners.forEach(((unique, id) -> {
if (unique.equals(Unique.HELMET)
|| unique.equals(Unique.CHESTPLATE)
|| unique.equals(Unique.LEGGINGS)
|| unique.equals(Unique.BOOTS)
) return;
if (id.equals(p.getUniqueId().toString())) {
Verbose.send(1, "They own the unique, checking if they have it: ", p.getInventory().contains(unique.getInGameItem()));
if (p.getInventory().contains(unique.getInGameItem())) {
Verbose.send(1, "They have it");
checks.add(true);
} else {
Verbose.send(1, "They don't have it");
checks.add(false);
}
}
}));
return !checks.contains(false);
}
}

View File

@@ -17,6 +17,25 @@ import java.util.function.Function;
public class Display implements Global {
public static void sphere(Location center, double radius, double verticalStep, double horizontalSpacing, Consumer<Location> action) {
for (double yOffset = -radius; yOffset <= radius; yOffset += verticalStep) {
double horizontalRadius = Math.sqrt(radius * radius - yOffset * yOffset);
if (horizontalRadius < 0.1) continue;
double circumference = 2 * Math.PI * horizontalRadius;
int points = Math.max(4, (int) (circumference / horizontalSpacing));
double angleStep = 360.0 / points;
for (double theta = 0; theta < 360; theta += angleStep) {
double x = Math.cos(Math.toRadians(theta)) * horizontalRadius;
double z = Math.sin(Math.toRadians(theta)) * horizontalRadius;
Location point = center.clone().add(x, yOffset, z);
action.accept(point);
}
}
}
public static final Function<Particle, Consumer<Location>> PARTICLE_FACTORY = particle -> l -> l.getWorld().spawnParticle(particle, l, 1, 0, 0, 0, 0);
public static final BiFunction<Color, Float, Consumer<Location>> DUST_PARTICLE_FACTORY = (color, thickness) -> {
Particle.DustOptions dust = new Particle.DustOptions(color, thickness);

View File

@@ -4,6 +4,11 @@ import me.trouper.armorsmp.ArmorSMP;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class Verbose {
public static void send(int backtrace, String message, Object... args) {
@@ -23,7 +28,9 @@ public class Verbose {
callerInfo = className + "." + caller.getMethodName();
}
if (ArmorSMP.getInstance().getManager().io.config.debuggerExclusions.contains(callerInfo)) {
return;
}
}
String formattedMessage = message.formatted(args);
@@ -53,7 +60,9 @@ public class Verbose {
callerInfo = className + "." + caller.getMethodName();
}
if (ArmorSMP.getInstance().getManager().io.config.debuggerExclusions.contains(callerInfo)) {
return;
}
}
String formattedMessage = message.formatted(args);

View File

@@ -2,14 +2,15 @@ package me.trouper.armorsmp.utils;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class WorldUtils {
public static boolean notDroppable(ItemStack i) {
return isArmor(i) && !isUnique(i) && !isChestplateUnique(i);
return isArmor(i) && !isUnique(i) && !isDragonEggEquivalent(i);
}
private static boolean isChestplateUnique(ItemStack i) {
private static boolean isDragonEggEquivalent(ItemStack i) {
Material m = i.getType();
return m.equals(Material.NETHERITE_CHESTPLATE);
}
@@ -26,9 +27,20 @@ public class WorldUtils {
public static boolean isUnique(ItemStack i) {
Material m = i.getType();
String n = m.name();
return n.contains("NETHERITE")
return (n.contains("NETHERITE") && isArmor(i))
|| n.contains("MACE")
|| n.contains("NETHERITE_SWORD")
|| n.contains("NETHERITE_AXE");
}
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;
ItemMeta meta1 = item1.getItemMeta();
ItemMeta meta2 = item2.getItemMeta();
return meta1 == null || meta2 == null || meta1.equals(meta2);
}
}