fix multiplayer: remove KNOCKED, swoon softlock, combat checks, dodge TP gate, inv cache, killfeed, threads/leaks
This commit is contained in:
@@ -17,12 +17,16 @@ public class AttackTpListener implements Listener {
|
||||
return null;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onAttack(EntityDamageByEntityEvent e) {
|
||||
Player p = getAttacker(e.getDamager());
|
||||
if (p == null) return;
|
||||
if (p.getGameMode() == org.bukkit.GameMode.SPECTATOR) return;
|
||||
if (!(e.getEntity() instanceof LivingEntity target)) return;
|
||||
if (e.isCancelled()) return;
|
||||
if (target instanceof Player tp) {
|
||||
if (tp.getGameMode() == org.bukkit.GameMode.CREATIVE || tp.getGameMode() == org.bukkit.GameMode.SPECTATOR) return;
|
||||
if (tp.isInvulnerable()) return;
|
||||
}
|
||||
tension.startBattle(p, target);
|
||||
boolean crit = false;
|
||||
if (e.getDamager() instanceof org.bukkit.entity.AbstractArrow arrow) crit = arrow.isCritical();
|
||||
@@ -46,7 +50,7 @@ public class AttackTpListener implements Listener {
|
||||
}
|
||||
|
||||
public void onDodge(Player p) {
|
||||
if (tension.isInBattle(p)) tension.addTP(p, 2.5f, "DODGE +1%");
|
||||
tension.tryGiveDodge(p);
|
||||
p.getWorld().spawnParticle(org.bukkit.Particle.DUST, p.getLocation().add(0, 0.25, 0), 25, 0.5, 0.05, 0.5, 0, new org.bukkit.Particle.DustOptions(org.bukkit.Color.fromRGB(255, 255, 255), 0.15f));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,14 @@ public class BlackKnifeListener implements Listener {
|
||||
|
||||
public BlackKnifeListener(BlackKnifePlugin plugin) { this.plugin = plugin; }
|
||||
|
||||
private String getMode(Player p) { return mode.getOrDefault(p.getUniqueId(), "STARS"); }
|
||||
public String getMode(Player p) { return mode.getOrDefault(p.getUniqueId(), "STARS"); }
|
||||
|
||||
public void cleanupPlayer(Player p) {
|
||||
mode.remove(p.getUniqueId());
|
||||
swordCombo.remove(p.getUniqueId());
|
||||
clearPreview(p);
|
||||
clearHighlight(p);
|
||||
}
|
||||
|
||||
public Location getGazePoint(Player p) {
|
||||
var ray = p.getWorld().rayTraceBlocks(p.getEyeLocation(), p.getEyeLocation().getDirection(), 120);
|
||||
@@ -153,6 +160,16 @@ public class BlackKnifeListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(org.bukkit.event.player.PlayerQuitEvent e) {
|
||||
cleanupPlayer(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDeath(org.bukkit.event.entity.PlayerDeathEvent e) {
|
||||
swordCombo.remove(e.getEntity().getUniqueId());
|
||||
}
|
||||
|
||||
private void clearPreview(Player p) {
|
||||
var task = previewTasks.remove(p.getUniqueId());
|
||||
if (task != null) task.cancel();
|
||||
@@ -169,7 +186,8 @@ public class BlackKnifeListener implements Listener {
|
||||
if (m.equals("SWORD")) {
|
||||
BukkitRunnable r = new BukkitRunnable() {
|
||||
@Override public void run() {
|
||||
if (!p.isOnline() || !getMode(p).equals("SWORD") || p.hasCooldown(Material.NETHERITE_SWORD)) return;
|
||||
if (!p.isOnline() || !getMode(p).equals("SWORD")) { previewTasks.remove(p.getUniqueId()); cancel(); return; }
|
||||
if (p.hasCooldown(Material.NETHERITE_SWORD)) return;
|
||||
if (!BlackKnifeItem.is(p.getInventory().getItemInMainHand()) && !BlackKnifeItem.is(p.getInventory().getItemInOffHand())) return;
|
||||
Vector dir = p.getEyeLocation().getDirection().normalize();
|
||||
Vector right = dir.clone().crossProduct(new Vector(0, 1, 0));
|
||||
@@ -290,6 +308,7 @@ public class BlackKnifeListener implements Listener {
|
||||
d.setBrightness(new Display.Brightness(15, 15));
|
||||
d.setViewRange(64);
|
||||
});
|
||||
EntityTracker.mark(disp);
|
||||
Vector vel = new Vector(0, -0.35 - Math.random() * 0.1, 0);
|
||||
vel.add(new Vector((Math.random() - 0.5) * 0.08, 0, (Math.random() - 0.5) * 0.08));
|
||||
new BukkitRunnable() {
|
||||
@@ -301,6 +320,7 @@ public class BlackKnifeListener implements Listener {
|
||||
if (next.getBlock().isSolid() || nl.getY() <= p.getWorld().getHighestBlockYAt(nl) + 0.5) {
|
||||
Location expl = cur.clone().add(vel.clone().normalize().multiply(-0.1));
|
||||
disp.teleport(expl);
|
||||
EntityTracker.untrack(disp);
|
||||
disp.remove();
|
||||
cancel();
|
||||
p.getWorld().spawnParticle(Particle.EXPLOSION, expl, 1);
|
||||
@@ -313,6 +333,7 @@ public class BlackKnifeListener implements Listener {
|
||||
d.setBrightness(new Display.Brightness(15, 15));
|
||||
d.setViewRange(64);
|
||||
});
|
||||
EntityTracker.mark(shard);
|
||||
new BukkitRunnable() {
|
||||
@Override public void run() {
|
||||
if (!shard.isValid()) { cancel(); return; }
|
||||
@@ -321,6 +342,7 @@ public class BlackKnifeListener implements Listener {
|
||||
if (n2.getBlock().isSolid()) {
|
||||
Location expl2 = cur2.clone().add(sv.clone().normalize().multiply(-0.1));
|
||||
shard.teleport(expl2);
|
||||
EntityTracker.untrack(shard);
|
||||
shard.remove();
|
||||
cancel();
|
||||
return;
|
||||
@@ -331,6 +353,7 @@ public class BlackKnifeListener implements Listener {
|
||||
if (ent instanceof Player pl && pl != p) continue;
|
||||
if (ent instanceof org.bukkit.entity.LivingEntity le && le != p) {
|
||||
DamageUtil.apply(p, le, 3.0);
|
||||
EntityTracker.untrack(shard);
|
||||
shard.remove();
|
||||
cancel();
|
||||
break;
|
||||
@@ -340,10 +363,11 @@ public class BlackKnifeListener implements Listener {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(n2);
|
||||
if (d2 > 0.25 && d2 < 0.81) {
|
||||
plugin.getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
plugin.getTension().tryGiveDodge(pl);
|
||||
pl.getWorld().spawnParticle(Particle.DUST, pl.getLocation().add(0, 0.25, 0), 25, 0.5, 0.05, 0.5, 0, new Particle.DustOptions(Color.fromRGB(255, 255, 255), 0.15f));
|
||||
}
|
||||
}
|
||||
EntityTracker.untrack(shard);
|
||||
if (shard.getTicksLived() > 40) { shard.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
@@ -356,10 +380,11 @@ public class BlackKnifeListener implements Listener {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(nl);
|
||||
if (d2 > 0.25 && d2 < 0.81) {
|
||||
plugin.getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
plugin.getTension().tryGiveDodge(pl);
|
||||
pl.getWorld().spawnParticle(Particle.DUST, pl.getLocation().add(0, 0.25, 0), 25, 0.5, 0.05, 0.5, 0, new Particle.DustOptions(Color.fromRGB(255, 255, 255), 0.15f));
|
||||
}
|
||||
}
|
||||
EntityTracker.untrack(disp);
|
||||
if (disp.getTicksLived() > 120) { disp.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
|
||||
@@ -10,6 +10,8 @@ public class BlackKnifePlugin extends JavaPlugin {
|
||||
private ChatConfig chatConfig;
|
||||
private ChatHandler chatHandler;
|
||||
private AwakeningManager awakeningManager;
|
||||
private BlackKnifeListener knifeListener;
|
||||
private SwoonHandler swoonHandler;
|
||||
private String lang = "ru";
|
||||
|
||||
@Override
|
||||
@@ -24,10 +26,11 @@ public class BlackKnifePlugin extends JavaPlugin {
|
||||
chatHandler = new ChatHandler(this, chatConfig);
|
||||
awakeningManager = new AwakeningManager(this, magicManager);
|
||||
getServer().getPluginManager().registerEvents(tension, this);
|
||||
getServer().getPluginManager().registerEvents(new BlackKnifeListener(this), this);
|
||||
getServer().getPluginManager().registerEvents(new SwoonHandler(this), this);
|
||||
knifeListener = new BlackKnifeListener(this);
|
||||
swoonHandler = new SwoonHandler(this);
|
||||
getServer().getPluginManager().registerEvents(knifeListener, this);
|
||||
getServer().getPluginManager().registerEvents(swoonHandler, this);
|
||||
getServer().getPluginManager().registerEvents(new AttackTpListener(tension), this);
|
||||
getServer().getPluginManager().registerEvents(new KnockedHandler(this), this);
|
||||
getServer().getPluginManager().registerEvents(new ParryHandler(this), this);
|
||||
getServer().getPluginManager().registerEvents(magicListener, this);
|
||||
getServer().getPluginManager().registerEvents(chatHandler, this);
|
||||
@@ -36,6 +39,7 @@ public class BlackKnifePlugin extends JavaPlugin {
|
||||
getCommand("blackknife").setExecutor(new BlackKnifeCommand(this, chatConfig, chatHandler));
|
||||
getCommand("magic").setExecutor(new MagicCommand(magicManager, this));
|
||||
getServer().getScheduler().runTaskTimer(this, () -> tension.tickShield(), 20L, 1L);
|
||||
cleanupLegacyKnocked();
|
||||
getLogger().info("BlackKnife 1.0.0 enabled - Paper 1.21.1 lang=" + lang);
|
||||
}
|
||||
|
||||
@@ -43,9 +47,30 @@ public class BlackKnifePlugin extends JavaPlugin {
|
||||
public TensionManager getTension() { return tension; }
|
||||
public MagicManager getMagicManager() { return magicManager; }
|
||||
public MagicListener getMagicListener() { return magicListener; }
|
||||
public BlackKnifeListener getKnifeListener() { return knifeListener; }
|
||||
public SwoonHandler getSwoonHandler() { return swoonHandler; }
|
||||
public String getLang() { return lang; }
|
||||
public void reloadLang() { lang = getConfig().getString("lang", "ru"); if (awakeningManager != null) awakeningManager.reloadChances(); }
|
||||
|
||||
private void cleanupLegacyKnocked() {
|
||||
try {
|
||||
var knocked = new org.bukkit.NamespacedKey("blackknife", "knocked");
|
||||
var vhp = new org.bukkit.NamespacedKey("blackknife", "vhp");
|
||||
for (var p : getServer().getOnlinePlayers()) {
|
||||
var pdc = p.getPersistentDataContainer();
|
||||
if (pdc.has(knocked, org.bukkit.persistence.PersistentDataType.BYTE)) {
|
||||
pdc.remove(knocked);
|
||||
pdc.remove(vhp);
|
||||
try { p.setWalkSpeed(0.2f); } catch (Exception ignored) {}
|
||||
p.removePotionEffect(org.bukkit.potion.PotionEffectType.WEAKNESS);
|
||||
p.removePotionEffect(org.bukkit.potion.PotionEffectType.SLOWNESS);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
getLogger().warning("Legacy knocked cleanup failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
getServer().getScheduler().cancelTasks(this);
|
||||
|
||||
@@ -5,7 +5,19 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
public class DamageUtil {
|
||||
public static boolean canHurt(Player attacker, LivingEntity victim) {
|
||||
if (victim == null || !victim.isValid() || victim.isDead()) return false;
|
||||
if (attacker != null && attacker.getGameMode() == org.bukkit.GameMode.SPECTATOR) return false;
|
||||
if (victim instanceof Player pl) {
|
||||
if (pl.getGameMode() == org.bukkit.GameMode.CREATIVE || pl.getGameMode() == org.bukkit.GameMode.SPECTATOR) return false;
|
||||
if (pl.isInvulnerable()) return false;
|
||||
if (pl.getPersistentDataContainer().has(SwoonHandler.SWOONED, PersistentDataType.BYTE)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void apply(Player attacker, LivingEntity victim, double amount) {
|
||||
if (!canHurt(attacker, victim)) return;
|
||||
victim.getPersistentDataContainer().set(SwoonHandler.MAGIC_DAMAGE, PersistentDataType.BYTE, (byte) 1);
|
||||
victim.damage(amount, attacker);
|
||||
victim.getPersistentDataContainer().remove(SwoonHandler.MAGIC_DAMAGE);
|
||||
|
||||
@@ -25,6 +25,7 @@ public class DiamondAttack {
|
||||
d.setBrightness(new Display.Brightness(15, 15));
|
||||
d.setViewRange(64);
|
||||
});
|
||||
EntityTracker.mark(crystal);
|
||||
p.getWorld().playSound(spawn, Sound.BLOCK_AMETHYST_BLOCK_PLACE, 1f, 0.9f);
|
||||
p.getWorld().playSound(spawn, Sound.BLOCK_AMETHYST_BLOCK_CHIME, 1f, 1.5f);
|
||||
Vector vel = dir.clone().multiply(1.5);
|
||||
@@ -39,6 +40,7 @@ public class DiamondAttack {
|
||||
if (hitBlock) {
|
||||
Location expl = cur.clone().add(vel.clone().normalize().multiply(-0.1));
|
||||
crystal.teleport(expl);
|
||||
EntityTracker.untrack(crystal);
|
||||
crystal.remove();
|
||||
cancel();
|
||||
expl.getWorld().spawnParticle(Particle.EXPLOSION, expl, 1);
|
||||
@@ -50,6 +52,7 @@ public class DiamondAttack {
|
||||
s.setBrightness(new Display.Brightness(15, 15));
|
||||
s.setViewRange(64);
|
||||
});
|
||||
EntityTracker.mark(shard);
|
||||
Vector sv = d.clone().multiply(0.4);
|
||||
new BukkitRunnable() {
|
||||
@Override public void run() {
|
||||
@@ -59,6 +62,7 @@ public class DiamondAttack {
|
||||
if (n2.getBlock().isSolid()) {
|
||||
Location expl2 = cur2.clone().add(sv.clone().normalize().multiply(-0.1));
|
||||
shard.teleport(expl2);
|
||||
EntityTracker.untrack(shard);
|
||||
shard.remove();
|
||||
cancel();
|
||||
return;
|
||||
@@ -68,6 +72,7 @@ public class DiamondAttack {
|
||||
for (var ent : n2.getWorld().getNearbyEntities(n2, 0.7, 0.7, 0.7, e -> e instanceof LivingEntity && e != p)) {
|
||||
LivingEntity le = (LivingEntity) ent;
|
||||
DamageUtil.apply(p, le, 2.0);
|
||||
EntityTracker.untrack(shard);
|
||||
shard.remove();
|
||||
cancel();
|
||||
break;
|
||||
@@ -76,10 +81,11 @@ public class DiamondAttack {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(n2);
|
||||
if (d2 > 0.25 && d2 < 0.81) {
|
||||
BlackKnifePlugin.getPlugin(BlackKnifePlugin.class).getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
BlackKnifePlugin.getPlugin(BlackKnifePlugin.class).getTension().tryGiveDodge(pl);
|
||||
pl.getWorld().spawnParticle(Particle.DUST, pl.getLocation().add(0, 0.25, 0), 25, 0.5, 0.05, 0.5, 0, new Particle.DustOptions(Color.fromRGB(255, 255, 255), 0.15f));
|
||||
}
|
||||
}
|
||||
EntityTracker.untrack(shard);
|
||||
if (shard.getTicksLived() > 40) { shard.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
@@ -100,12 +106,13 @@ public class DiamondAttack {
|
||||
if (pl == p) continue;
|
||||
double d = pl.getLocation().add(0, 1, 0).distanceSquared(nl);
|
||||
if (d > 0.25 && d < 0.81) {
|
||||
BlackKnifePlugin.getPlugin(BlackKnifePlugin.class).getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
BlackKnifePlugin.getPlugin(BlackKnifePlugin.class).getTension().tryGiveDodge(pl);
|
||||
pl.getWorld().spawnParticle(Particle.DUST, pl.getLocation().add(0, 0.25, 0), 25, 0.5, 0.05, 0.5, 0, new Particle.DustOptions(Color.fromRGB(255, 255, 255), 0.15f));
|
||||
}
|
||||
}
|
||||
if (hit) {
|
||||
Location expl = nl.clone();
|
||||
EntityTracker.untrack(crystal);
|
||||
crystal.remove();
|
||||
cancel();
|
||||
expl.getWorld().spawnParticle(Particle.EXPLOSION, expl, 1);
|
||||
@@ -117,6 +124,7 @@ public class DiamondAttack {
|
||||
s.setBrightness(new Display.Brightness(15, 15));
|
||||
s.setViewRange(64);
|
||||
});
|
||||
EntityTracker.mark(shard);
|
||||
Vector sv = d.clone().multiply(0.4);
|
||||
new BukkitRunnable() {
|
||||
@Override public void run() {
|
||||
@@ -126,6 +134,7 @@ public class DiamondAttack {
|
||||
if (n2.getBlock().isSolid()) {
|
||||
Location expl2 = cur2.clone().add(sv.clone().normalize().multiply(-0.1));
|
||||
shard.teleport(expl2);
|
||||
EntityTracker.untrack(shard);
|
||||
shard.remove();
|
||||
cancel();
|
||||
return;
|
||||
@@ -134,20 +143,23 @@ public class DiamondAttack {
|
||||
shard.getWorld().spawnParticle(Particle.CRIT, n2, 1, 0.05, 0.05, 0.05, 0);
|
||||
for (var ent : n2.getWorld().getNearbyEntities(n2, 0.7, 0.7, 0.7, e -> e instanceof LivingEntity && e != p)) {
|
||||
LivingEntity le = (LivingEntity) ent;
|
||||
EntityTracker.untrack(shard);
|
||||
DamageUtil.apply(p, le, 2.0); shard.remove(); cancel(); break;
|
||||
}
|
||||
for (Player pl : n2.getWorld().getNearbyPlayers(n2, 0.9)) {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(n2);
|
||||
if (d2 > 0.25 && d2 < 0.81) {
|
||||
BlackKnifePlugin.getPlugin(BlackKnifePlugin.class).getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
BlackKnifePlugin.getPlugin(BlackKnifePlugin.class).getTension().tryGiveDodge(pl);
|
||||
pl.getWorld().spawnParticle(Particle.DUST, pl.getLocation().add(0, 0.25, 0), 25, 0.5, 0.05, 0.5, 0, new Particle.DustOptions(Color.fromRGB(255, 255, 255), 0.15f));
|
||||
}
|
||||
}
|
||||
EntityTracker.untrack(shard);
|
||||
if (shard.getTicksLived() > 40) { shard.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
}
|
||||
EntityTracker.untrack(crystal);
|
||||
} else if (crystal.getTicksLived() > 60) { crystal.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
|
||||
@@ -61,6 +61,7 @@ public class DiamondTripleAttack {
|
||||
int steps = Math.max(1, (int)Math.ceil(vel.length()/0.5));
|
||||
for (int s=0;s<=steps;s++) {
|
||||
Location check = cur.clone().add(vel.clone().multiply((double)s/steps));
|
||||
EntityTracker.untrack(shard);
|
||||
if (check.getBlock().isSolid()) { shard.remove(); cancel(); return; }
|
||||
}
|
||||
shard.teleport(nl);
|
||||
@@ -71,13 +72,15 @@ public class DiamondTripleAttack {
|
||||
DamageUtil.apply(p, le, 7.0);
|
||||
le.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.SLOWNESS,20,0,false,false,true));
|
||||
nl.getWorld().spawnParticle(Particle.CRIT, le.getLocation().add(0,1,0),8,0.3,0.3,0.3,0.1);
|
||||
EntityTracker.untrack(shard);
|
||||
shard.remove(); cancel(); return;
|
||||
}
|
||||
for (Player pl : nl.getWorld().getNearbyPlayers(nl,0.9)) {
|
||||
if (pl==p) continue;
|
||||
double d2 = pl.getLocation().add(0,1,0).distanceSquared(nl);
|
||||
if (d2>0.25 && d2<0.81) plugin.getTension().addTP(pl,2.5f,"DODGE +1%");
|
||||
if (d2>0.25 && d2<0.81) plugin.getTension().tryGiveDodge(pl);
|
||||
}
|
||||
EntityTracker.untrack(shard);
|
||||
if (nl.distanceSquared(spawn) > 1600 || shard.getTicksLived() > 80) { shard.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin,1L,1L);
|
||||
|
||||
@@ -27,10 +27,7 @@ public class EntityTracker {
|
||||
var mat = bd.getBlock().getMaterial();
|
||||
if (mat == org.bukkit.Material.DEEPSLATE_TILES || mat == org.bukkit.Material.SCULK_CATALYST || mat == org.bukkit.Material.AMETHYST_BLOCK || mat == org.bukkit.Material.MEDIUM_AMETHYST_BUD) isBk = true;
|
||||
}
|
||||
if (e instanceof org.bukkit.entity.TextDisplay td) {
|
||||
if (td.getPersistentDataContainer().has(new NamespacedKey("blackknife", "knocked"), PersistentDataType.BYTE)) isBk = true;
|
||||
}
|
||||
if (isBk) { e.remove(); count++; }
|
||||
if (isBk) { untrack(e); e.remove(); count++; }
|
||||
}
|
||||
}
|
||||
for (var uuid : new java.util.HashSet<>(tracked)) {
|
||||
|
||||
@@ -7,7 +7,6 @@ import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import java.util.Random;
|
||||
|
||||
public class KillMessageHandler implements Listener {
|
||||
@@ -49,18 +48,17 @@ public class KillMessageHandler implements Listener {
|
||||
}
|
||||
|
||||
private String detectMagic(Player killer, Player victim) {
|
||||
var lastDamage = victim.getLastDamageCause();
|
||||
if (lastDamage != null && lastDamage.getCause() != null) {
|
||||
Component killerName = Component.text(killer.getName());
|
||||
if (SwoonHandler.isSwooned(victim)) return "SWOON";
|
||||
var ml = plugin.getMagicListener();
|
||||
if (ml != null) {
|
||||
MagicType last = ml.getLastCast(killer, 10000L);
|
||||
if (last != null) return last.display;
|
||||
}
|
||||
if (killer.getPersistentDataContainer().has(SwoonHandler.SWOONED, PersistentDataType.BYTE)) return "SWOON";
|
||||
if (BlackKnifeItem.is(killer.getInventory().getItemInMainHand()) || BlackKnifeItem.is(killer.getInventory().getItemInOffHand())) {
|
||||
String mode = killer.getPersistentDataContainer().has(BlackKnifeItem.MODE, PersistentDataType.STRING) ? killer.getPersistentDataContainer().get(BlackKnifeItem.MODE, PersistentDataType.STRING) : "Black Knife";
|
||||
var kl = plugin.getKnifeListener();
|
||||
String mode = kl != null ? kl.getMode(killer) : "Black Knife";
|
||||
return mode != null ? mode : "Black Knife";
|
||||
}
|
||||
for (MagicType mt : MagicType.values()) {
|
||||
if (killer.hasCooldown(org.bukkit.Material.AMETHYST_SHARD)) return mt.display;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -79,13 +77,16 @@ public class KillMessageHandler implements Listener {
|
||||
}
|
||||
|
||||
private Component replaceFirst(Component in, String target, Component repl) {
|
||||
String plain = net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer.plainText().serialize(in);
|
||||
int idx = plain.indexOf(target);
|
||||
if (idx < 0) return in;
|
||||
String before = plain.substring(0, idx);
|
||||
String after = plain.substring(idx + target.length());
|
||||
Component out = Component.text(before).append(repl).append(Component.text(after));
|
||||
return out;
|
||||
try {
|
||||
return in.replaceText(b -> b.matchLiteral(target).once().replacement(repl));
|
||||
} catch (Exception e) {
|
||||
String plain = net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer.plainText().serialize(in);
|
||||
int idx = plain.indexOf(target);
|
||||
if (idx < 0) return in;
|
||||
String before = plain.substring(0, idx);
|
||||
String after = plain.substring(idx + target.length());
|
||||
return Component.text(before).append(repl).append(Component.text(after));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRu() {
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
package me.sashegdev.blackknife;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Display;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.TextDisplay;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class KnockedHandler implements Listener {
|
||||
private final BlackKnifePlugin plugin;
|
||||
private final NamespacedKey KNOCKED = new NamespacedKey("blackknife", "knocked");
|
||||
private final NamespacedKey VHP = new NamespacedKey("blackknife", "vhp");
|
||||
private final Map<UUID, TextDisplay> displays = new HashMap<>();
|
||||
|
||||
public KnockedHandler(BlackKnifePlugin plugin) { this.plugin = plugin; }
|
||||
|
||||
@EventHandler
|
||||
public void onDamage(EntityDamageEvent e) {
|
||||
if (!(e.getEntity() instanceof Player p)) return;
|
||||
if (p.getPersistentDataContainer().has(KNOCKED, PersistentDataType.BYTE)) {
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
double dmg = e.getFinalDamage();
|
||||
double health = p.getHealth();
|
||||
if (dmg < health) return;
|
||||
var nearby = p.getWorld().getNearbyEntities(p.getLocation(), 8, 8, 8, en -> en instanceof Player && en != p && !((Player)en).getPersistentDataContainer().has(KNOCKED, PersistentDataType.BYTE));
|
||||
long attackers = 0;
|
||||
if (e instanceof org.bukkit.event.entity.EntityDamageByEntityEvent ev && ev.getDamager() instanceof Player) attackers = 1;
|
||||
boolean hasAlly = !nearby.isEmpty();
|
||||
if (!hasAlly) {
|
||||
return;
|
||||
}
|
||||
e.setCancelled(true);
|
||||
double vhp = health - dmg;
|
||||
p.getPersistentDataContainer().set(KNOCKED, PersistentDataType.BYTE, (byte) 1);
|
||||
p.getPersistentDataContainer().set(VHP, PersistentDataType.DOUBLE, vhp);
|
||||
p.setHealth(1.0);
|
||||
p.setWalkSpeed(0f);
|
||||
p.addPotionEffect(new org.bukkit.potion.PotionEffect(PotionEffectType.WEAKNESS, 100000, 10, false, false));
|
||||
TextDisplay td = p.getWorld().spawn(p.getLocation().add(0, 2.4, 0), TextDisplay.class, d -> {
|
||||
d.text(Component.text(String.format("%.0f HP", vhp)).color(vhp < 0 ? NamedTextColor.RED : NamedTextColor.YELLOW));
|
||||
d.setBillboard(Display.Billboard.CENTER);
|
||||
d.setSeeThrough(true);
|
||||
d.setShadowed(true);
|
||||
d.setBackgroundColor(org.bukkit.Color.fromARGB(64, 0, 0, 0));
|
||||
d.setAlignment(TextDisplay.TextAlignment.CENTER);
|
||||
});
|
||||
displays.put(p.getUniqueId(), td);
|
||||
p.sendActionBar(Component.text(String.format("KNOCKED %.0f HP - regen potion to revive", vhp)).color(NamedTextColor.RED));
|
||||
plugin.getServer().getScheduler().runTaskTimer(plugin, task -> {
|
||||
TextDisplay d = displays.get(p.getUniqueId());
|
||||
if (d == null || !p.isOnline() || !p.getPersistentDataContainer().has(KNOCKED, PersistentDataType.BYTE)) { task.cancel(); return; }
|
||||
d.teleport(p.getLocation().add(0, 2.4, 0));
|
||||
if (p.isDead()) { d.remove(); task.cancel(); }
|
||||
}, 2L, 2L);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onMove(PlayerMoveEvent e) {
|
||||
Player p = e.getPlayer();
|
||||
if (!p.getPersistentDataContainer().has(KNOCKED, PersistentDataType.BYTE)) return;
|
||||
if (e.getFrom().distanceSquared(e.getTo()) < 0.01) return;
|
||||
double dx = e.getTo().getX() - e.getFrom().getX();
|
||||
double dz = e.getTo().getZ() - e.getFrom().getZ();
|
||||
if (Math.abs(dx) > 0.1 || Math.abs(dz) > 0.1) {
|
||||
e.setCancelled(true);
|
||||
p.sendActionBar(Component.text("Knocked - can't move, regen potion to revive").color(NamedTextColor.RED));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPotionSplash(org.bukkit.event.entity.PotionSplashEvent e) {
|
||||
if (e.getPotion().getEffects().stream().noneMatch(ef -> ef.getType().equals(PotionEffectType.REGENERATION))) return;
|
||||
for (LivingEntity ent : e.getAffectedEntities()) {
|
||||
if (!(ent instanceof Player p)) continue;
|
||||
if (!p.getPersistentDataContainer().has(KNOCKED, PersistentDataType.BYTE)) continue;
|
||||
double intensity = e.getIntensity(p);
|
||||
double heal = 4 * intensity;
|
||||
Double vhp = p.getPersistentDataContainer().get(VHP, PersistentDataType.DOUBLE);
|
||||
if (vhp == null) vhp = -10.0;
|
||||
double newVhp = vhp + heal;
|
||||
p.getPersistentDataContainer().set(VHP, PersistentDataType.DOUBLE, newVhp);
|
||||
TextDisplay td = displays.get(p.getUniqueId());
|
||||
if (td != null) td.text(Component.text(String.format("%.0f HP", newVhp)).color(newVhp < 0 ? NamedTextColor.RED : NamedTextColor.GREEN));
|
||||
if (newVhp >= 1) {
|
||||
p.getPersistentDataContainer().remove(KNOCKED);
|
||||
p.getPersistentDataContainer().remove(VHP);
|
||||
p.setHealth(1.0);
|
||||
p.setWalkSpeed(0.2f);
|
||||
p.removePotionEffect(PotionEffectType.WEAKNESS);
|
||||
p.removePotionEffect(PotionEffectType.SLOWNESS);
|
||||
if (td != null) { td.remove(); displays.remove(p.getUniqueId()); }
|
||||
p.sendActionBar(Component.text("Revived!").color(NamedTextColor.GREEN));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDeath(PlayerDeathEvent e) {
|
||||
displays.remove(e.getEntity().getUniqueId());
|
||||
}
|
||||
}
|
||||
@@ -39,11 +39,13 @@ public class LungeAttack {
|
||||
d.setBrightness(new Display.Brightness(15, 15));
|
||||
d.setViewRange(64);
|
||||
});
|
||||
EntityTracker.mark(catalyst);
|
||||
p.getWorld().playSound(start, Sound.BLOCK_SCULK_CATALYST_BLOOM, 1f, 0.7f);
|
||||
double catSpeed = 3.0;
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override public void run() {
|
||||
EntityTracker.untrack(catalyst);
|
||||
if (!target.isValid() || target.isDead()) { if (catalyst.isValid()) catalyst.remove(); cancel(); return; }
|
||||
if (!catalyst.isValid()) { cancel(); return; }
|
||||
Location cur = catalyst.getLocation();
|
||||
@@ -55,6 +57,7 @@ public class LungeAttack {
|
||||
nl.getWorld().spawnParticle(Particle.DUST, nl, 1, 0, 0, 0, 0, new Particle.DustOptions(Color.fromRGB(20, 60, 80), 1f));
|
||||
if (nl.distanceSquared(tpos) < 4) {
|
||||
catalyst.teleport(tpos);
|
||||
EntityTracker.untrack(catalyst);
|
||||
catalyst.remove();
|
||||
cancel();
|
||||
tpos.getWorld().spawnParticle(Particle.EXPLOSION, tpos, 1);
|
||||
@@ -62,6 +65,7 @@ public class LungeAttack {
|
||||
tpos.getWorld().playSound(tpos, Sound.ENTITY_WARDEN_SONIC_BOOM, 1f, 0.6f);
|
||||
startPhase1(p, tpos, target, plugin);
|
||||
}
|
||||
EntityTracker.untrack(catalyst);
|
||||
if (catalyst.getTicksLived() > 80) { catalyst.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
@@ -149,6 +153,7 @@ public class LungeAttack {
|
||||
new org.joml.Vector3f(1.5f, 1.5f, 1.5f),
|
||||
new org.joml.AxisAngle4f()));
|
||||
});
|
||||
EntityTracker.mark(sword);
|
||||
new BukkitRunnable() {
|
||||
long hold = 5;
|
||||
boolean launched = false;
|
||||
@@ -172,6 +177,7 @@ public class LungeAttack {
|
||||
int steps = Math.max(1, (int) Math.ceil(aim.length() / 0.5));
|
||||
for (int s = 0; s <= steps; s++) {
|
||||
Location check = cur.clone().add(aim.clone().multiply((double) s / steps));
|
||||
EntityTracker.untrack(sword);
|
||||
if (check.getBlock().isSolid()) { sword.remove(); cancel(); return; }
|
||||
}
|
||||
sword.teleport(nl);
|
||||
@@ -179,13 +185,15 @@ public class LungeAttack {
|
||||
if (le == p) continue;
|
||||
applyLungeDamage(le, p, damage);
|
||||
le.getWorld().spawnParticle(Particle.CRIT, le.getLocation().add(0, 1, 0), 10, 0.4, 0.4, 0.4, 0.1);
|
||||
EntityTracker.untrack(sword);
|
||||
sword.remove(); cancel(); return;
|
||||
}
|
||||
for (Player pl : nl.getWorld().getNearbyPlayers(nl, 0.9)) {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(nl);
|
||||
if (d2 > 0.25 && d2 < 0.81) plugin.getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
if (d2 > 0.25 && d2 < 0.81) plugin.getTension().tryGiveDodge(pl);
|
||||
}
|
||||
EntityTracker.untrack(sword);
|
||||
if (sword.getTicksLived() > 80) { sword.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
@@ -235,6 +243,7 @@ public class LungeAttack {
|
||||
nl.getWorld().spawnParticle(Particle.SCULK_SOUL, nl, 1, 0.05, 0.05, 0.05, 0);
|
||||
if (nl.getY() <= gazePoint.getY() + 0.5 || nl.getBlock().isSolid()) {
|
||||
Location expl = gazePoint.clone();
|
||||
EntityTracker.untrack(sword);
|
||||
sword.remove(); cancel();
|
||||
expl.getWorld().spawnParticle(Particle.EXPLOSION, expl, 1);
|
||||
expl.getWorld().spawnParticle(Particle.SMOKE, expl, 10, 0.3, 0.1, 0.3, 0.02);
|
||||
@@ -254,7 +263,7 @@ public class LungeAttack {
|
||||
for (Player pl : expl.getWorld().getNearbyPlayers(expl, 2.5)) {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(expl);
|
||||
if (d2 > 0.25 && d2 < 6.5) plugin.getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
if (d2 > 0.25 && d2 < 6.5) plugin.getTension().tryGiveDodge(pl);
|
||||
}
|
||||
expl.getWorld().playSound(expl, Sound.ENTITY_GENERIC_EXPLODE, 0.8f, 1.2f);
|
||||
return;
|
||||
@@ -262,8 +271,10 @@ public class LungeAttack {
|
||||
for (LivingEntity le : nl.getWorld().getNearbyLivingEntities(nl, 1.0)) {
|
||||
if (le == p) continue;
|
||||
applyLungeDamage(le, p, 20);
|
||||
EntityTracker.untrack(sword);
|
||||
sword.remove(); cancel(); return;
|
||||
}
|
||||
EntityTracker.untrack(sword);
|
||||
if (sword.getTicksLived() > 60) { sword.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
@@ -271,6 +282,7 @@ public class LungeAttack {
|
||||
}
|
||||
|
||||
private static void applyLungeDamage(LivingEntity ent, Player attacker, double amount) {
|
||||
if (!DamageUtil.canHurt(attacker, ent)) return;
|
||||
if (ent instanceof Player pl && pl.isBlocking()) amount /= 2.5;
|
||||
ent.getPersistentDataContainer().set(SwoonHandler.MAGIC_DAMAGE, PersistentDataType.BYTE, (byte) 1);
|
||||
ent.damage(amount, attacker);
|
||||
@@ -357,6 +369,7 @@ public class LungeAttack {
|
||||
new org.joml.Vector3f(0.7f, 0.7f, 0.7f),
|
||||
new org.joml.AxisAngle4f()));
|
||||
});
|
||||
EntityTracker.mark(sword);
|
||||
Vector vel = new Vector(0, -fallSpeed, 0);
|
||||
p.getWorld().playSound(spawn, Sound.ENTITY_PLAYER_ATTACK_SWEEP, 0.6f, 0.7f);
|
||||
new BukkitRunnable() {
|
||||
@@ -369,6 +382,7 @@ public class LungeAttack {
|
||||
nl.getWorld().spawnParticle(Particle.SCULK_SOUL, nl, 1, 0.05, 0.05, 0.05, 0);
|
||||
if (nl.getY() <= target.getY() + 0.5 || nl.getBlock().isSolid()) {
|
||||
Location expl = nl.clone();
|
||||
EntityTracker.untrack(sword);
|
||||
sword.remove();
|
||||
cancel();
|
||||
expl.getWorld().spawnParticle(Particle.SMOKE, expl, 6, 0.2, 0.1, 0.2, 0.02);
|
||||
@@ -387,7 +401,7 @@ public class LungeAttack {
|
||||
for (Player pl : expl.getWorld().getNearbyPlayers(expl, 0.9)) {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(expl);
|
||||
if (d2 > 0.25 && d2 < 0.81) plugin.getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
if (d2 > 0.25 && d2 < 0.81) plugin.getTension().tryGiveDodge(pl);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -395,8 +409,10 @@ public class LungeAttack {
|
||||
if (le == p) continue;
|
||||
applyLungeDamage(le, p, damage);
|
||||
le.getWorld().spawnParticle(Particle.CRIT, le.getLocation().add(0, 1, 0), 8, 0.3, 0.3, 0.3, 0.1);
|
||||
EntityTracker.untrack(sword);
|
||||
sword.remove(); cancel(); return;
|
||||
}
|
||||
EntityTracker.untrack(sword);
|
||||
if (sword.getTicksLived() > 80) { sword.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
@@ -446,6 +462,7 @@ public class LungeAttack {
|
||||
new org.joml.Vector3f(1.5f, 1.5f, 1.5f),
|
||||
new org.joml.AxisAngle4f()));
|
||||
});
|
||||
EntityTracker.mark(sword);
|
||||
spawn.getWorld().playSound(spawn, Sound.ENTITY_PLAYER_ATTACK_SWEEP, 0.8f, 0.5f);
|
||||
|
||||
new BukkitRunnable() {
|
||||
@@ -472,6 +489,7 @@ public class LungeAttack {
|
||||
int steps = Math.max(1, (int) Math.ceil(aim.length() / 0.5));
|
||||
for (int s = 0; s <= steps; s++) {
|
||||
Location check = cur.clone().add(aim.clone().multiply((double) s / steps));
|
||||
EntityTracker.untrack(sword);
|
||||
if (check.getBlock().isSolid()) { sword.remove(); cancel(); return; }
|
||||
}
|
||||
sword.teleport(nl);
|
||||
@@ -479,13 +497,15 @@ public class LungeAttack {
|
||||
if (le == p) continue;
|
||||
applyLungeDamage(le, p, 20);
|
||||
le.getWorld().spawnParticle(Particle.CRIT, le.getLocation().add(0, 1, 0), 10, 0.4, 0.4, 0.4, 0.1);
|
||||
EntityTracker.untrack(sword);
|
||||
sword.remove(); cancel(); return;
|
||||
}
|
||||
for (Player pl : nl.getWorld().getNearbyPlayers(nl, 0.9)) {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(nl);
|
||||
if (d2 > 0.25 && d2 < 0.81) plugin.getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
if (d2 > 0.25 && d2 < 0.81) plugin.getTension().tryGiveDodge(pl);
|
||||
}
|
||||
EntityTracker.untrack(sword);
|
||||
if (sword.getTicksLived() > 80) { sword.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
|
||||
@@ -28,9 +28,24 @@ public class MagicListener implements Listener {
|
||||
private final MagicManager mgr;
|
||||
private final Map<UUID, Long> shieldEnd = new HashMap<>();
|
||||
private final Map<UUID, BukkitRunnable> shieldTasks = new HashMap<>();
|
||||
private final Map<UUID, MagicType> lastCast = new HashMap<>();
|
||||
private final Map<UUID, Long> lastCastTime = new HashMap<>();
|
||||
|
||||
public MagicListener(BlackKnifePlugin plugin, MagicManager mgr) { this.plugin = plugin; this.mgr = mgr; }
|
||||
|
||||
public void recordCast(Player p, MagicType mt) {
|
||||
lastCast.put(p.getUniqueId(), mt);
|
||||
lastCastTime.put(p.getUniqueId(), System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public MagicType getLastCast(Player p, long withinMs) {
|
||||
MagicType mt = lastCast.get(p.getUniqueId());
|
||||
Long t = lastCastTime.get(p.getUniqueId());
|
||||
if (mt == null || t == null) return null;
|
||||
if (System.currentTimeMillis() - t > withinMs) return null;
|
||||
return mt;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
Player p = e.getPlayer();
|
||||
@@ -133,9 +148,10 @@ public class MagicListener implements Listener {
|
||||
else if (mt == MagicType.SHIELDO) ok = castShieldo(p, tm);
|
||||
if (ok) {
|
||||
tm.setTP(p, tm.getTP(p) - mt.cost);
|
||||
prof.casts++; prof.tpSpent += mt.cost; mgr.save(prof);
|
||||
mgr.recordCast(prof, mt.cost); mgr.save(prof);
|
||||
p.setCooldown(Material.AMETHYST_SHARD, mt.cd);
|
||||
MagicItem.updateLore(item, prof);
|
||||
recordCast(p, mt);
|
||||
}
|
||||
e.setCancelled(true);
|
||||
}
|
||||
@@ -159,6 +175,7 @@ public class MagicListener implements Listener {
|
||||
if (check.getBlock().isSolid()) {
|
||||
Location expl = cur.clone().add(vel.clone().normalize().multiply(Math.max(0, (double)(s-1)/steps)));
|
||||
for (int k=0;k<12;k++){ double a=(double)k/12*Math.PI*2; for(int h=-1;h<=1;h++){ Location sphere=expl.clone().add(Math.cos(a)*0.5, h*0.25, Math.sin(a)*0.5); sphere.getWorld().spawnParticle(Particle.DUST, sphere,1,0,0,0,0,new Particle.DustOptions(Color.fromRGB(180,40,40),1f)); sphere.getWorld().spawnParticle(Particle.SMOKE,sphere,1,0.02,0.02,0.02,0);} } expl.getWorld().spawnParticle(Particle.CRIT,expl,6,0.2,0.2,0.2,0.05); expl.getWorld().playSound(expl,Sound.BLOCK_STONE_BREAK,1f,0.8f);
|
||||
EntityTracker.untrack(marker);
|
||||
marker.remove(); cancel(); return;
|
||||
}
|
||||
}
|
||||
@@ -170,8 +187,10 @@ public class MagicListener implements Listener {
|
||||
Location hit=le.getLocation().add(0,1,0);
|
||||
for(int k=0;k<12;k++){ double a=(double)k/12*Math.PI*2; for(int h=-1;h<=1;h++){ Location s=hit.clone().add(Math.cos(a)*0.5,h*0.25,Math.sin(a)*0.5); s.getWorld().spawnParticle(Particle.DUST,s,1,0,0,0,0,new Particle.DustOptions(Color.fromRGB(200,40,40),0.9f)); } } hit.getWorld().spawnParticle(Particle.CRIT,hit,10,0.3,0.3,0.3,0.1); hit.getWorld().playSound(hit,Sound.ENTITY_PLAYER_ATTACK_CRIT,1f,0.9f);
|
||||
le.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.SLOWNESS,40,1,false,false,true));
|
||||
EntityTracker.untrack(marker);
|
||||
marker.remove(); cancel(); return;
|
||||
}
|
||||
EntityTracker.untrack(marker);
|
||||
if (marker.getTicksLived()>80){ marker.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin,1L,1L);
|
||||
@@ -197,6 +216,7 @@ public class MagicListener implements Listener {
|
||||
if (check.getBlock().isSolid()) {
|
||||
Location expl = cur.clone().add(vel.clone().normalize().multiply(Math.max(0, (double)(s-1)/steps)));
|
||||
for(int k=0;k<12;k++){ double a=(double)k/12*Math.PI*2; for(int h=-1;h<=1;h++){ Location sphere=expl.clone().add(Math.cos(a)*0.5,h*0.25,Math.sin(a)*0.5); sphere.getWorld().spawnParticle(Particle.SNOWFLAKE,sphere,1,0.02,0.02,0.02,0); sphere.getWorld().spawnParticle(Particle.DUST,sphere,1,0,0,0,0,new Particle.DustOptions(Color.fromRGB(136,204,255),0.9f)); } } expl.getWorld().spawnParticle(Particle.SNOWFLAKE,expl,10,0.3,0.3,0.3,0.1); expl.getWorld().playSound(expl,Sound.BLOCK_GLASS_BREAK,1f,1.2f);
|
||||
EntityTracker.untrack(marker);
|
||||
marker.remove(); cancel(); return;
|
||||
}
|
||||
}
|
||||
@@ -208,8 +228,10 @@ public class MagicListener implements Listener {
|
||||
Location hit=le.getLocation().add(0,1,0);
|
||||
for(int k=0;k<12;k++){ double a=(double)k/12*Math.PI*2; for(int h=-1;h<=1;h++){ Location s=hit.clone().add(Math.cos(a)*0.5,h*0.25,Math.sin(a)*0.5); s.getWorld().spawnParticle(Particle.SNOWFLAKE,s,1,0.02,0.02,0.02,0); } } hit.getWorld().spawnParticle(Particle.SNOWFLAKE,hit,8,0.3,0.3,0.3,0.1); hit.getWorld().playSound(hit,Sound.BLOCK_GLASS_BREAK,1f,0.7f);
|
||||
le.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.SLOWNESS,40,1,false,false,true));
|
||||
EntityTracker.untrack(marker);
|
||||
marker.remove(); cancel(); return;
|
||||
}
|
||||
EntityTracker.untrack(marker);
|
||||
if (marker.getTicksLived()>80){ marker.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin,1L,1L);
|
||||
@@ -271,4 +293,18 @@ public class MagicListener implements Listener {
|
||||
p.getWorld().playSound(p.getLocation(), Sound.ITEM_SHIELD_BLOCK, 0.8f, 1.3f);
|
||||
return dmg * 0.7;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(org.bukkit.event.player.PlayerQuitEvent e) {
|
||||
var task = shieldTasks.remove(e.getPlayer().getUniqueId());
|
||||
if (task != null) task.cancel();
|
||||
shieldEnd.remove(e.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDeath(org.bukkit.event.entity.PlayerDeathEvent e) {
|
||||
var task = shieldTasks.remove(e.getEntity().getUniqueId());
|
||||
if (task != null) task.cancel();
|
||||
shieldEnd.remove(e.getEntity().getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@ package me.sashegdev.blackknife;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MagicManager {
|
||||
private final BlackKnifePlugin plugin;
|
||||
private final Map<UUID, MagicProfile> map = new HashMap<>();
|
||||
private final Map<UUID, MagicProfile> map = new java.util.concurrent.ConcurrentHashMap<>();
|
||||
private File folder;
|
||||
|
||||
public MagicManager(BlackKnifePlugin plugin) {
|
||||
@@ -51,7 +50,7 @@ public class MagicManager {
|
||||
return p != null && p.awakened;
|
||||
}
|
||||
|
||||
public MagicProfile awaken(Player p, String cause) {
|
||||
public synchronized MagicProfile awaken(Player p, String cause) {
|
||||
MagicProfile prof = map.get(p.getUniqueId());
|
||||
if (prof == null) prof = new MagicProfile(p.getName(), p.getUniqueId());
|
||||
prof.nick = p.getName();
|
||||
@@ -71,7 +70,7 @@ public class MagicManager {
|
||||
return prof;
|
||||
}
|
||||
|
||||
public MagicProfile getOrCreate(Player p) {
|
||||
public synchronized MagicProfile getOrCreate(Player p) {
|
||||
MagicProfile prof = map.get(p.getUniqueId());
|
||||
if (prof == null) {
|
||||
prof = new MagicProfile(p.getName(), p.getUniqueId());
|
||||
@@ -87,26 +86,59 @@ public class MagicManager {
|
||||
public MagicProfile get(UUID uuid) { return map.get(uuid); }
|
||||
|
||||
public void save(MagicProfile prof) {
|
||||
final String nick;
|
||||
final long firstSeen;
|
||||
final int casts;
|
||||
final double tpSpent;
|
||||
final int heals;
|
||||
final int selectedIdx;
|
||||
final java.util.List<String> common;
|
||||
final java.util.List<String> rare;
|
||||
final java.util.List<String> story;
|
||||
final boolean rareRolled;
|
||||
final boolean awakened;
|
||||
final String cause;
|
||||
final long at;
|
||||
synchronized (prof) {
|
||||
nick = prof.nick;
|
||||
firstSeen = prof.firstSeen;
|
||||
casts = prof.casts;
|
||||
tpSpent = prof.tpSpent;
|
||||
heals = prof.heals;
|
||||
selectedIdx = prof.selectedIdx;
|
||||
common = new java.util.ArrayList<>(prof.common);
|
||||
rare = new java.util.ArrayList<>(prof.rare);
|
||||
story = new java.util.ArrayList<>(prof.story);
|
||||
rareRolled = prof.rareRolled;
|
||||
awakened = prof.awakened;
|
||||
cause = prof.awakeningCause;
|
||||
at = prof.awakenedAt;
|
||||
}
|
||||
try {
|
||||
File f = new File(folder, prof.uuid.toString() + ".yml");
|
||||
YamlConfiguration y = new YamlConfiguration();
|
||||
y.set("nick", prof.nick);
|
||||
y.set("nick", nick);
|
||||
y.set("uuid", prof.uuid.toString());
|
||||
y.set("firstSeen", prof.firstSeen);
|
||||
y.set("stats.casts", prof.casts);
|
||||
y.set("stats.tpSpent", prof.tpSpent);
|
||||
y.set("stats.heals", prof.heals);
|
||||
y.set("pack.common", prof.common);
|
||||
y.set("pack.rare", prof.rare);
|
||||
y.set("pack.story", prof.story);
|
||||
y.set("pack.selected", prof.selectedIdx);
|
||||
y.set("flags.rareRolled", prof.rareRolled);
|
||||
y.set("flags.awakened", prof.awakened);
|
||||
y.set("flags.cause", prof.awakeningCause);
|
||||
y.set("flags.at", prof.awakenedAt);
|
||||
y.set("firstSeen", firstSeen);
|
||||
y.set("stats.casts", casts);
|
||||
y.set("stats.tpSpent", tpSpent);
|
||||
y.set("stats.heals", heals);
|
||||
y.set("pack.common", common);
|
||||
y.set("pack.rare", rare);
|
||||
y.set("pack.story", story);
|
||||
y.set("pack.selected", selectedIdx);
|
||||
y.set("flags.rareRolled", rareRolled);
|
||||
y.set("flags.awakened", awakened);
|
||||
y.set("flags.cause", cause);
|
||||
y.set("flags.at", at);
|
||||
y.save(f);
|
||||
} catch (Exception e) { plugin.getLogger().warning("Failed save magic " + prof.uuid + ": " + e.getMessage()); }
|
||||
}
|
||||
|
||||
public void saveAll() { for (MagicProfile p : map.values()) save(p); }
|
||||
public synchronized void recordCast(MagicProfile prof, double cost) {
|
||||
prof.casts++;
|
||||
prof.tpSpent += cost;
|
||||
}
|
||||
|
||||
public void saveAll() { for (MagicProfile p : new java.util.ArrayList<>(map.values())) save(p); }
|
||||
}
|
||||
|
||||
@@ -14,10 +14,12 @@ public class ParryHandler implements Listener {
|
||||
private final BlackKnifePlugin plugin;
|
||||
public ParryHandler(BlackKnifePlugin plugin) { this.plugin = plugin; }
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onDamage(EntityDamageByEntityEvent e) {
|
||||
if (!(e.getEntity() instanceof Player victim)) return;
|
||||
if (e.isCancelled()) return;
|
||||
if (victim.getGameMode() == org.bukkit.GameMode.CREATIVE || victim.getGameMode() == org.bukkit.GameMode.SPECTATOR) return;
|
||||
if (victim.isInvulnerable()) return;
|
||||
if (victim.getPersistentDataContainer().has(SwoonHandler.SWOONED, PersistentDataType.BYTE)) return;
|
||||
if (BlackKnifeItem.is(victim.getInventory().getItemInMainHand()) || BlackKnifeItem.is(victim.getInventory().getItemInOffHand())) {
|
||||
TensionManager tm = plugin.getTension();
|
||||
if (tm.getTP(victim) < 37.5f) return;
|
||||
|
||||
@@ -57,13 +57,16 @@ public class PhantomBarrageAttack {
|
||||
Vector toTarget = target.clone().subtract(cur).toVector().normalize().multiply(1.6);
|
||||
Location nl = cur.clone().add(toTarget);
|
||||
int steps = Math.max(1,(int)Math.ceil(toTarget.length()/0.5));
|
||||
EntityTracker.untrack(orb);
|
||||
for(int s=0;s<=steps;s++){ Location check=cur.clone().add(toTarget.clone().multiply((double)s/steps)); if(check.getBlock().isSolid()){orb.remove();cancel();return;} }
|
||||
orb.teleport(nl);
|
||||
cur = nl;
|
||||
nl.getWorld().spawnParticle(Particle.DUST, nl,1,0,0,0,0,new Particle.DustOptions(Color.fromRGB(30,10,50),1.2f));
|
||||
nl.getWorld().spawnParticle(Particle.SCULK_SOUL, nl,1,0.05,0.05,0.05,0);
|
||||
EntityTracker.untrack(orb);
|
||||
for(LivingEntity le: nl.getWorld().getNearbyLivingEntities(nl,0.9)){ if(le==p) continue; DamageUtil.apply(p, le, 6.0); le.getWorld().spawnParticle(Particle.CRIT, le.getLocation().add(0,1,0),8,0.3,0.3,0.3,0.1); orb.remove(); cancel(); return; }
|
||||
for(Player pl: nl.getWorld().getNearbyPlayers(nl,0.9)){ if(pl==p) continue; double d2=pl.getLocation().add(0,1,0).distanceSquared(nl); if(d2>0.25 && d2<0.81) plugin.getTension().addTP(pl,2.5f,"DODGE +1%"); }
|
||||
for(Player pl: nl.getWorld().getNearbyPlayers(nl,0.9)){ if(pl==p) continue; double d2=pl.getLocation().add(0,1,0).distanceSquared(nl); if(d2>0.25 && d2<0.81) plugin.getTension().tryGiveDodge(pl); }
|
||||
EntityTracker.untrack(orb);
|
||||
if(cur.distanceSquared(target) < 1 || orb.getTicksLived() > 100){ orb.remove(); cancel(); }
|
||||
ticks++;
|
||||
}
|
||||
|
||||
@@ -34,43 +34,31 @@ public class SwoonHandler implements Listener {
|
||||
|
||||
public SwoonHandler(BlackKnifePlugin plugin) { this.plugin = plugin; }
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onHit(org.bukkit.event.entity.EntityDamageByEntityEvent e) {
|
||||
if (!(e.getDamager() instanceof Player p)) return;
|
||||
if (p.getGameMode() == org.bukkit.GameMode.SPECTATOR) return;
|
||||
if (!BlackKnifeItem.is(p.getInventory().getItemInMainHand()) && !BlackKnifeItem.is(p.getInventory().getItemInOffHand())) return;
|
||||
if (!(e.getEntity() instanceof LivingEntity target)) return;
|
||||
if (target.getPersistentDataContainer().has(MAGIC_DAMAGE, PersistentDataType.BYTE)) {
|
||||
target.getPersistentDataContainer().remove(MAGIC_DAMAGE);
|
||||
return;
|
||||
}
|
||||
if (target.getPersistentDataContainer().has(SWOONED, PersistentDataType.BYTE)) return;
|
||||
if (target instanceof Player vt) {
|
||||
if (vt.getGameMode() == org.bukkit.GameMode.CREATIVE || vt.getGameMode() == org.bukkit.GameMode.SPECTATOR) return;
|
||||
if (vt.isInvulnerable()) return;
|
||||
}
|
||||
if (p.hasCooldown(Material.NETHERITE_SWORD)) return;
|
||||
e.setCancelled(true);
|
||||
plugin.getTension().setTP(p, Math.max(0, plugin.getTension().getTP(p) - 125f));
|
||||
if (target instanceof Player tp) {
|
||||
double maxHp = tp.getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue();
|
||||
var attr = tp.getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH);
|
||||
double maxHp = attr != null ? attr.getValue() : 20.0;
|
||||
double vhpTmp = tp.getHealth() - 999;
|
||||
double vhp = Math.max(-2147483648.0, Math.min(maxHp, vhpTmp));
|
||||
final double finalVhp = vhp;
|
||||
tp.setHealth(1.0);
|
||||
tp.setWalkSpeed(0f);
|
||||
tp.getPersistentDataContainer().set(SWOONED, PersistentDataType.BYTE, (byte) 1);
|
||||
tp.getPersistentDataContainer().set(VHP, PersistentDataType.DOUBLE, vhp);
|
||||
tp.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, 100000, 10, false, false, true));
|
||||
tp.addPotionEffect(new PotionEffect(PotionEffectType.JUMP_BOOST, 100000, 128, false, false, true));
|
||||
tp.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, 100000, 10, false, false, true));
|
||||
tp.addPotionEffect(new PotionEffect(PotionEffectType.DARKNESS, 100000, 0, false, false, true));
|
||||
tp.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 100, 0, false, false, true));
|
||||
TextDisplay td = tp.getWorld().spawn(tp.getLocation().add(0, 2.4, 0), TextDisplay.class, d -> {
|
||||
d.text(Component.text(String.format("%.0f HP", finalVhp)).color(NamedTextColor.DARK_RED));
|
||||
d.setBillboard(Display.Billboard.CENTER);
|
||||
d.setSeeThrough(true);
|
||||
d.setShadowed(true);
|
||||
d.setBackgroundColor(org.bukkit.Color.fromARGB(64, 40, 0, 0));
|
||||
d.setAlignment(TextDisplay.TextAlignment.CENTER);
|
||||
d.getPersistentDataContainer().set(SWOONED, PersistentDataType.BYTE, (byte)1);
|
||||
});
|
||||
EntityTracker.mark(td);
|
||||
displays.put(tp.getUniqueId(), td);
|
||||
applySwoon(tp, vhp);
|
||||
tp.getWorld().spawnParticle(org.bukkit.Particle.SOUL, tp.getLocation().add(0,1,0), 40, 0.5,0.5,0.5,0.05);
|
||||
tp.getWorld().spawnParticle(org.bukkit.Particle.SCULK_SOUL, tp.getLocation().add(0,1,0), 15, 0.5,0.5,0.5,0.02);
|
||||
tp.getWorld().spawnParticle(org.bukkit.Particle.ASH, tp.getLocation().add(0,1,0), 20, 0.5,0.5,0.5,0);
|
||||
@@ -80,14 +68,7 @@ public class SwoonHandler implements Listener {
|
||||
tp.getWorld().playSound(tp.getLocation(), Sound.ENTITY_WARDEN_SONIC_BOOM, 1f, 0.5f);
|
||||
tp.getWorld().playSound(tp.getLocation(), Sound.ENTITY_ELDER_GUARDIAN_CURSE, 1f, 0.7f);
|
||||
if (Math.random() < 0.1) tp.getWorld().dropItemNaturally(tp.getLocation(), BlackKnifeItem.create());
|
||||
plugin.getServer().getScheduler().runTaskTimer(plugin, task -> {
|
||||
TextDisplay d = displays.get(tp.getUniqueId());
|
||||
if (d == null || !tp.isOnline() || !tp.getPersistentDataContainer().has(SWOONED, PersistentDataType.BYTE)) { task.cancel(); return; }
|
||||
d.teleport(tp.getLocation().add(0, 2.4, 0));
|
||||
Double cur = tp.getPersistentDataContainer().get(VHP, PersistentDataType.DOUBLE);
|
||||
if (cur != null) d.text(Component.text(String.format("%.0f HP", cur)).color(cur < 0 ? NamedTextColor.DARK_RED : NamedTextColor.YELLOW));
|
||||
if (tp.isDead()) { d.remove(); task.cancel(); }
|
||||
}, 2L, 2L);
|
||||
startDisplayTask(tp);
|
||||
} else {
|
||||
target.getPersistentDataContainer().set(MAGIC_DAMAGE, PersistentDataType.BYTE, (byte) 1);
|
||||
target.damage(999.0, p);
|
||||
@@ -154,31 +135,120 @@ public class SwoonHandler implements Listener {
|
||||
Double vhp = p.getPersistentDataContainer().get(VHP, PersistentDataType.DOUBLE);
|
||||
if (vhp == null) vhp = -10.0;
|
||||
double newVhp = vhp + heal;
|
||||
double maxHp = p.getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue();
|
||||
var attr = p.getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH);
|
||||
double maxHp = attr != null ? attr.getValue() : 20.0;
|
||||
newVhp = Math.min(maxHp, newVhp);
|
||||
p.getPersistentDataContainer().set(VHP, PersistentDataType.DOUBLE, newVhp);
|
||||
TextDisplay td = displays.get(p.getUniqueId());
|
||||
if (td != null) td.text(Component.text(String.format("%.0f HP", newVhp)).color(newVhp < 0 ? NamedTextColor.DARK_RED : newVhp < 1 ? NamedTextColor.YELLOW : NamedTextColor.GREEN));
|
||||
if (td != null && td.isValid()) td.text(Component.text(String.format("%.0f HP", newVhp)).color(newVhp < 0 ? NamedTextColor.DARK_RED : newVhp < 1 ? NamedTextColor.YELLOW : NamedTextColor.GREEN));
|
||||
if (newVhp >= 1) {
|
||||
p.getPersistentDataContainer().remove(SWOONED);
|
||||
p.getPersistentDataContainer().remove(VHP);
|
||||
p.setHealth(Math.min(newVhp, maxHp));
|
||||
p.setWalkSpeed(0.2f);
|
||||
p.removePotionEffect(PotionEffectType.SLOWNESS);
|
||||
p.removePotionEffect(PotionEffectType.JUMP_BOOST);
|
||||
p.removePotionEffect(PotionEffectType.WEAKNESS);
|
||||
p.removePotionEffect(PotionEffectType.DARKNESS);
|
||||
if (td != null) { td.remove(); displays.remove(p.getUniqueId()); }
|
||||
p.sendActionBar(Component.text("Revived from SWOON!").color(NamedTextColor.GREEN));
|
||||
p.getWorld().playSound(p.getLocation(), Sound.BLOCK_BEACON_ACTIVATE, 1f, 1.2f);
|
||||
revive(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applySwoon(Player tp, double vhp) {
|
||||
tp.setHealth(1.0);
|
||||
try { tp.setWalkSpeed(0f); } catch (Exception ignored) {}
|
||||
tp.getPersistentDataContainer().set(SWOONED, PersistentDataType.BYTE, (byte) 1);
|
||||
tp.getPersistentDataContainer().set(VHP, PersistentDataType.DOUBLE, vhp);
|
||||
tp.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, 100000, 10, false, false, true));
|
||||
tp.addPotionEffect(new PotionEffect(PotionEffectType.JUMP_BOOST, 100000, 128, false, false, true));
|
||||
tp.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, 100000, 10, false, false, true));
|
||||
tp.addPotionEffect(new PotionEffect(PotionEffectType.DARKNESS, 100000, 0, false, false, true));
|
||||
tp.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 100, 0, false, false, true));
|
||||
TextDisplay old = displays.remove(tp.getUniqueId());
|
||||
if (old != null && old.isValid()) { EntityTracker.untrack(old); old.remove(); }
|
||||
TextDisplay td = tp.getWorld().spawn(tp.getLocation().add(0, 2.4, 0), TextDisplay.class, d -> {
|
||||
d.text(Component.text(String.format("%.0f HP", vhp)).color(NamedTextColor.DARK_RED));
|
||||
d.setBillboard(Display.Billboard.CENTER);
|
||||
d.setSeeThrough(true);
|
||||
d.setShadowed(true);
|
||||
d.setBackgroundColor(org.bukkit.Color.fromARGB(64, 40, 0, 0));
|
||||
d.setAlignment(TextDisplay.TextAlignment.CENTER);
|
||||
d.getPersistentDataContainer().set(SWOONED, PersistentDataType.BYTE, (byte) 1);
|
||||
});
|
||||
EntityTracker.mark(td);
|
||||
displays.put(tp.getUniqueId(), td);
|
||||
}
|
||||
|
||||
private void startDisplayTask(Player tp) {
|
||||
plugin.getServer().getScheduler().runTaskTimer(plugin, task -> {
|
||||
TextDisplay d = displays.get(tp.getUniqueId());
|
||||
if (d == null || !d.isValid() || !tp.isOnline() || !tp.getPersistentDataContainer().has(SWOONED, PersistentDataType.BYTE)) {
|
||||
if (d != null && !d.isValid()) displays.remove(tp.getUniqueId());
|
||||
task.cancel();
|
||||
return;
|
||||
}
|
||||
d.teleport(tp.getLocation().add(0, 2.4, 0));
|
||||
Double cur = tp.getPersistentDataContainer().get(VHP, PersistentDataType.DOUBLE);
|
||||
if (cur != null) d.text(Component.text(String.format("%.0f HP", cur)).color(cur < 0 ? NamedTextColor.DARK_RED : NamedTextColor.YELLOW));
|
||||
if (tp.isDead()) { EntityTracker.untrack(d); d.remove(); displays.remove(tp.getUniqueId()); task.cancel(); }
|
||||
}, 2L, 2L);
|
||||
}
|
||||
|
||||
public void revive(Player p) {
|
||||
Double stored = p.getPersistentDataContainer().get(VHP, PersistentDataType.DOUBLE);
|
||||
p.getPersistentDataContainer().remove(SWOONED);
|
||||
p.getPersistentDataContainer().remove(VHP);
|
||||
var attr = p.getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH);
|
||||
double maxHp = attr != null ? attr.getValue() : 20.0;
|
||||
double hp = stored != null ? Math.min(Math.max(stored, 1.0), maxHp) : 1.0;
|
||||
try { p.setHealth(hp); } catch (Exception ignored) {}
|
||||
try { p.setWalkSpeed(0.2f); } catch (Exception ignored) {}
|
||||
p.removePotionEffect(PotionEffectType.SLOWNESS);
|
||||
p.removePotionEffect(PotionEffectType.JUMP_BOOST);
|
||||
p.removePotionEffect(PotionEffectType.WEAKNESS);
|
||||
p.removePotionEffect(PotionEffectType.DARKNESS);
|
||||
p.removePotionEffect(PotionEffectType.BLINDNESS);
|
||||
TextDisplay td = displays.remove(p.getUniqueId());
|
||||
if (td != null && td.isValid()) { EntityTracker.untrack(td); td.remove(); }
|
||||
p.sendActionBar(Component.text("Revived from SWOON!").color(NamedTextColor.GREEN));
|
||||
p.getWorld().playSound(p.getLocation(), Sound.BLOCK_BEACON_ACTIVATE, 1f, 1.2f);
|
||||
}
|
||||
|
||||
public void cleanupOffline(Player p) {
|
||||
TextDisplay td = displays.remove(p.getUniqueId());
|
||||
if (td != null && td.isValid()) { EntityTracker.untrack(td); td.remove(); }
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(org.bukkit.event.player.PlayerQuitEvent e) {
|
||||
cleanupOffline(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(org.bukkit.event.player.PlayerJoinEvent e) {
|
||||
Player p = e.getPlayer();
|
||||
if (!p.getPersistentDataContainer().has(SWOONED, PersistentDataType.BYTE)) return;
|
||||
Double vhp = p.getPersistentDataContainer().get(VHP, PersistentDataType.DOUBLE);
|
||||
if (vhp == null) { p.getPersistentDataContainer().remove(SWOONED); try { p.setWalkSpeed(0.2f); } catch (Exception ignored) {} return; }
|
||||
applySwoon(p, vhp);
|
||||
startDisplayTask(p);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onRespawn(org.bukkit.event.player.PlayerRespawnEvent e) {
|
||||
Player p = e.getPlayer();
|
||||
if (!p.getPersistentDataContainer().has(SWOONED, PersistentDataType.BYTE)) return;
|
||||
p.getPersistentDataContainer().remove(SWOONED);
|
||||
p.getPersistentDataContainer().remove(VHP);
|
||||
try { p.setWalkSpeed(0.2f); } catch (Exception ignored) {}
|
||||
p.removePotionEffect(PotionEffectType.SLOWNESS);
|
||||
p.removePotionEffect(PotionEffectType.JUMP_BOOST);
|
||||
p.removePotionEffect(PotionEffectType.WEAKNESS);
|
||||
p.removePotionEffect(PotionEffectType.DARKNESS);
|
||||
p.removePotionEffect(PotionEffectType.BLINDNESS);
|
||||
cleanupOffline(p);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDeath(PlayerDeathEvent e) {
|
||||
displays.remove(e.getEntity().getUniqueId());
|
||||
e.getEntity().getPersistentDataContainer().remove(SWOONED);
|
||||
Player p = e.getEntity();
|
||||
TextDisplay td = displays.remove(p.getUniqueId());
|
||||
if (td != null && td.isValid()) { EntityTracker.untrack(td); td.remove(); }
|
||||
p.getPersistentDataContainer().remove(SWOONED);
|
||||
p.getPersistentDataContainer().remove(VHP);
|
||||
}
|
||||
|
||||
public static boolean isSwooned(LivingEntity e) {
|
||||
|
||||
@@ -57,6 +57,7 @@ public class SwordAttack {
|
||||
}
|
||||
expl.getWorld().spawnParticle(Particle.CRIT, expl, 6, 0.2, 0.2, 0.2, 0.05);
|
||||
expl.getWorld().playSound(expl, Sound.BLOCK_STONE_BREAK, 1f, 0.8f);
|
||||
EntityTracker.untrack(marker);
|
||||
marker.remove();
|
||||
cancel();
|
||||
return;
|
||||
@@ -84,6 +85,7 @@ public class SwordAttack {
|
||||
hit.getWorld().playSound(hit, Sound.ENTITY_PLAYER_ATTACK_CRIT, 1f, 0.9f);
|
||||
le.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.SLOWNESS, 40, 1, false, false, true));
|
||||
le.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.WEAKNESS, 30, 0, false, false, true));
|
||||
EntityTracker.untrack(marker);
|
||||
marker.remove();
|
||||
cancel();
|
||||
return;
|
||||
@@ -92,11 +94,13 @@ public class SwordAttack {
|
||||
if (pl == p) continue;
|
||||
double d = pl.getLocation().add(0, 1, 0).distanceSquared(nl);
|
||||
if (d > 0.25 && d < 0.81) {
|
||||
BlackKnifePlugin.getPlugin(BlackKnifePlugin.class).getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
BlackKnifePlugin.getPlugin(BlackKnifePlugin.class).getTension().tryGiveDodge(pl);
|
||||
pl.getWorld().spawnParticle(Particle.DUST, pl.getLocation().add(0, 0.25, 0), 25, 0.5, 0.05, 0.5, 0, new Particle.DustOptions(Color.fromRGB(255, 255, 255), 0.15f));
|
||||
}
|
||||
}
|
||||
EntityTracker.untrack(marker);
|
||||
if (nl.distanceSquared(p.getEyeLocation()) > 14400) { marker.remove(); cancel(); return; }
|
||||
EntityTracker.untrack(marker);
|
||||
if (marker.getTicksLived() > 80) { marker.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
|
||||
@@ -20,6 +20,20 @@ public class TensionManager implements Listener {
|
||||
private final Map<UUID, Long> blockStart = new HashMap<>();
|
||||
private final Map<UUID, Long> lastCombat = new HashMap<>();
|
||||
private final Map<UUID, java.util.Set<UUID>> battleEnemies = new HashMap<>();
|
||||
private final Map<UUID, Long> lastDodge = new HashMap<>();
|
||||
private final Map<UUID, Boolean> ownerCache = new HashMap<>();
|
||||
private final Map<UUID, Long> ownerCacheTime = new HashMap<>();
|
||||
private static final long OWNER_CACHE_TTL = 2000L;
|
||||
|
||||
public boolean tryGiveDodge(Player pl) {
|
||||
if (!isInBattle(pl)) return false;
|
||||
long now = System.currentTimeMillis();
|
||||
Long last = lastDodge.get(pl.getUniqueId());
|
||||
if (last != null && now - last < 1000) return false;
|
||||
lastDodge.put(pl.getUniqueId(), now);
|
||||
addTP(pl, 2.5f, "DODGE +1%");
|
||||
return true;
|
||||
}
|
||||
|
||||
public float getTP(Player p) { return tp.getOrDefault(p.getUniqueId(), 0f); }
|
||||
|
||||
@@ -39,7 +53,21 @@ public class TensionManager implements Listener {
|
||||
}
|
||||
|
||||
public boolean isOwner(Player p) {
|
||||
return BlackKnifeItem.is(p.getInventory().getItemInMainHand()) || BlackKnifeItem.is(p.getInventory().getItemInOffHand()) || hasAnyBlackKnife(p);
|
||||
if (BlackKnifeItem.is(p.getInventory().getItemInMainHand()) || BlackKnifeItem.is(p.getInventory().getItemInOffHand())) return true;
|
||||
long now = System.currentTimeMillis();
|
||||
UUID id = p.getUniqueId();
|
||||
Long t = ownerCacheTime.get(id);
|
||||
Boolean cached = ownerCache.get(id);
|
||||
if (cached != null && t != null && now - t < OWNER_CACHE_TTL) return cached;
|
||||
boolean has = hasAnyBlackKnife(p);
|
||||
ownerCache.put(id, has);
|
||||
ownerCacheTime.put(id, now);
|
||||
return has;
|
||||
}
|
||||
|
||||
public void invalidateOwnerCache(Player p) {
|
||||
ownerCache.remove(p.getUniqueId());
|
||||
ownerCacheTime.remove(p.getUniqueId());
|
||||
}
|
||||
|
||||
private boolean hasAnyBlackKnife(Player p) {
|
||||
@@ -48,7 +76,8 @@ public class TensionManager implements Listener {
|
||||
}
|
||||
|
||||
public boolean hasMagic(Player p) {
|
||||
if (hasAnyBlackKnife(p)) return true;
|
||||
if (BlackKnifeItem.is(p.getInventory().getItemInMainHand()) || BlackKnifeItem.is(p.getInventory().getItemInOffHand())) return true;
|
||||
if (isOwner(p)) return true;
|
||||
var mgr = BlackKnifePlugin.getInstance() != null ? BlackKnifePlugin.getInstance().getMagicManager() : null;
|
||||
return mgr != null && mgr.hasAwakened(p.getUniqueId());
|
||||
}
|
||||
@@ -115,7 +144,8 @@ public class TensionManager implements Listener {
|
||||
public void tickShield() {
|
||||
long now = System.currentTimeMillis();
|
||||
for (Player p : org.bukkit.Bukkit.getOnlinePlayers()) {
|
||||
if (hasHeldShield(p)) {
|
||||
boolean blocking = hasHeldShield(p);
|
||||
if (blocking) {
|
||||
long start = blockStart.getOrDefault(p.getUniqueId(), now);
|
||||
if (!blockStart.containsKey(p.getUniqueId())) blockStart.put(p.getUniqueId(), now);
|
||||
if (now - start >= 5000) {
|
||||
@@ -123,7 +153,7 @@ public class TensionManager implements Listener {
|
||||
blockStart.put(p.getUniqueId(), now);
|
||||
lastCombat.put(p.getUniqueId(), now);
|
||||
}
|
||||
} else if (!hasHeldShield(p)) {
|
||||
} else {
|
||||
blockStart.remove(p.getUniqueId());
|
||||
}
|
||||
if (isOwner(p)) {
|
||||
@@ -139,10 +169,38 @@ public class TensionManager implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent e) { updateBar(e.getPlayer(), getTP(e.getPlayer())); }
|
||||
public void onJoin(PlayerJoinEvent e) { updateBar(e.getPlayer(), getTP(e.getPlayer())); invalidateOwnerCache(e.getPlayer()); }
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent e) { bars.remove(e.getPlayer().getUniqueId()); }
|
||||
public void onQuit(PlayerQuitEvent e) {
|
||||
UUID id = e.getPlayer().getUniqueId();
|
||||
BossBar bar = bars.remove(id);
|
||||
if (bar != null) bar.removeViewer(e.getPlayer());
|
||||
ownerCache.remove(id);
|
||||
ownerCacheTime.remove(id);
|
||||
blockStart.remove(id);
|
||||
lastDodge.remove(id);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInvChange(org.bukkit.event.inventory.InventoryClickEvent e) {
|
||||
if (e.getWhoClicked() instanceof Player p) invalidateOwnerCache(p);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPickup(org.bukkit.event.entity.EntityPickupItemEvent e) {
|
||||
if (e.getEntity() instanceof Player p) invalidateOwnerCache(p);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDrop(org.bukkit.event.player.PlayerDropItemEvent e) {
|
||||
invalidateOwnerCache(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onHeld(org.bukkit.event.player.PlayerItemHeldEvent e) {
|
||||
invalidateOwnerCache(e.getPlayer());
|
||||
}
|
||||
|
||||
public void hideAll() {
|
||||
for (var e : new HashMap<>(bars).entrySet()) {
|
||||
@@ -153,6 +211,9 @@ public class TensionManager implements Listener {
|
||||
for (var pl : org.bukkit.Bukkit.getOnlinePlayers()) bar.removeViewer(pl);
|
||||
}
|
||||
}
|
||||
bars.clear();
|
||||
blockStart.clear();
|
||||
lastDodge.clear();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
||||
Reference in New Issue
Block a user