Squashed commit of the following:

commit 5bd49a4e2feebe07a75ffbca440bf23ac5cfa8ea
Author: Piecuuu <56731916+Piecuuu@users.noreply.github.com>
Date:   Mon Feb 23 18:21:46 2026 +0100

    commands for best ks

commit 251cec40ac405d21e080f2a4c2638c8803237b43
Author: Piecuuu <56731916+Piecuuu@users.noreply.github.com>
Date:   Mon Feb 23 18:21:35 2026 +0100

    add ks + best ks placeholder (for tablist)

commit 713e30b19bc52db3ed77f21854d6566cd6ea8c6b
Author: Piecuuu <56731916+Piecuuu@users.noreply.github.com>
Date:   Mon Feb 23 16:53:36 2026 +0100

    refactor + best ks
This commit is contained in:
Piecuuu 2026-02-23 18:23:08 +01:00
parent 3fe1638e41
commit 21577f8e1d
4 changed files with 145 additions and 19 deletions

View file

@ -32,6 +32,14 @@ public class KillstreakCommand {
.then(Commands.argument("profile", ArgumentTypes.playerProfiles())
.requires(s -> s.getSender().hasPermission("ks.admin.get"))
.executes(KillstreakCommand::getOtherKillstreak)
.then(Commands.literal("best")
.requires(s -> s.getSender().hasPermission("ks.admin.get.best"))
.executes(KillstreakCommand::getOtherBestKillstreak)
)
)
.then(Commands.literal("best")
.requires(s -> s.getSender().hasPermission("ks.get.best"))
.executes(KillstreakCommand::getOwnBestKillstreak)
)
)
.then(Commands.literal("set")
@ -42,7 +50,12 @@ public class KillstreakCommand {
)
.then(Commands.literal("reset")
.requires(s -> s.getSender().hasPermission("ks.admin.reset"))
.then(playerArgument.executes(KillstreakCommand::resetKillstreak))
.then(playerArgument
.executes(KillstreakCommand::resetKillstreak)
.then(Commands.literal("best")
.executes(KillstreakCommand::resetBestKillstreak)
)
)
);
return ks.build();
@ -62,6 +75,27 @@ public class KillstreakCommand {
return offlinePlayer;
}
private static int getOwnBestKillstreak(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
final Entity entity = ctx.getSource().getExecutor();
if(!(entity instanceof Player p)) return 0;
KillstreakManager km = KillstreakManager.getInstance();
final long killstreak = km.getBestKillstreak(p);
ctx.getSource().getSender().sendMessage(km.getBestKillstreakComponent(killstreak));
return 1;
}
private static int getOtherBestKillstreak(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
final OfflinePlayer offlinePlayer = getOfflinePlayerFromCtx(ctx);
KillstreakManager km = KillstreakManager.getInstance();
final long killstreak = km.getBestKillstreak(offlinePlayer);
ctx.getSource().getSender().sendMessage(km.getBestKillstreakComponent(killstreak));
return 1;
}
private static int resetKillstreak(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
final Player player = getFirstPlayerFromCtx(ctx);
KillstreakManager km = KillstreakManager.getInstance();
@ -72,6 +106,16 @@ public class KillstreakCommand {
return 1;
}
private static int resetBestKillstreak(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
final Player player = getFirstPlayerFromCtx(ctx);
KillstreakManager km = KillstreakManager.getInstance();
km.setBestKillstreak(player, 0L);
ctx.getSource().getSender().sendMessage(km.getBestKillstreakComponent(0L));
return 1;
}
private static int setKillstreak(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
final Player player = getFirstPlayerFromCtx(ctx);
final long killstreak = LongArgumentType.getLong(ctx, "killstreak");

View file

@ -2,6 +2,9 @@ package pl.piecuu.killstreak;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@ -45,8 +48,44 @@ public class KillstreakExpansion extends PlaceholderExpansion {
final Component output = km.getKillstreakComponent(killstreak);
return MiniMessage.miniMessage().serialize(output);
} else if(identifier.equalsIgnoreCase("killstreak_tab")) {
KillstreakManager km = KillstreakManager.getInstance();
final long killstreak = km.getInvisKillstreak(p);
final long bestKillstreak = km.getBestKillstreak(p);
final Component bestComponent = km.getBestKillstreakComponent(bestKillstreak);
if(killstreak == 0 && bestKillstreak > 0)
return MiniMessage.miniMessage().serialize(bestComponent);
else if(killstreak == 0) return "";
Component output = km.getKillstreakComponent(killstreak);
if(bestKillstreak > killstreak) {
output = output
.appendSpace()
.append(Component.text("|", TextColor.color(
KillstreakExpansion.mix(
output.children().getLast().color(),
bestComponent.children().getFirst().color(),
0.6
)
)).decoration(TextDecoration.BOLD, true))
.appendSpace()
.append(bestComponent);
}
return MiniMessage.miniMessage().serialize(output);
}
return null;
}
private static TextColor mix(TextColor c1, TextColor c2, double ratio) {
ratio = Math.max(0, Math.min(1, ratio));
double inverse = 1.0 - ratio;
int r = (int) (c1.red() * inverse + c2.red() * ratio);
int g = (int) (c1.green() * inverse + c2.green() * ratio);
int b = (int) (c1.blue() * inverse + c2.blue() * ratio);
return TextColor.color(r, g, b);
}
}

View file

@ -1,5 +1,7 @@
package pl.piecuu.killstreak;
import java.util.Map;
import org.bukkit.NamespacedKey;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
@ -8,6 +10,7 @@ import org.bukkit.persistence.PersistentDataType;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.format.TextDecoration.State;
import pl.piecuu.invisninja.InvisNinja;
public class KillstreakManager {
@ -16,6 +19,7 @@ public class KillstreakManager {
return instance;
}
public NamespacedKey playerKillstreakKey;
public NamespacedKey playerBestKillstreakKey;
public NamespacedKey playerInvisKSKey;
@SuppressWarnings("unused")
@ -25,28 +29,43 @@ public class KillstreakManager {
instance = this;
this.playerKillstreakKey = new NamespacedKey(plugin, "playerKillstreakKey");
this.playerInvisKSKey = new NamespacedKey(plugin, "playerInvisKSKey");
this.playerBestKillstreakKey = new NamespacedKey(plugin, "playerBestKillstreakKey");
}
public long getBestKillstreak(OfflinePlayer player) {
return this.getLongFromPDC(player, playerBestKillstreakKey);
}
public void setBestKillstreak(Player player, long bestKillstreak) {
this.setLongFromPDC(player, playerBestKillstreakKey, bestKillstreak);
}
public void normaliseBestKillstreak(Player player) {
long killstreak = this.getKillstreak(player);
this.setBestKillstreak(player, killstreak);
}
public void setKillstreak(Player player, long streak) {
if(streak < 0) return;
player.getPersistentDataContainer().set(playerKillstreakKey, PersistentDataType.LONG, streak);
if(Killstreak.getInvisNinja() == null || !InvisNinja.isPlayerInvisible(player)) {
setInvisKillstreak(player, streak);
}
this.setLongFromPDC(player, playerKillstreakKey, streak);
}
public void setInvisKillstreak(Player player, long streak) {
if(streak < 0) return;
player.getPersistentDataContainer().set(playerInvisKSKey, PersistentDataType.LONG, streak);
this.setLongFromPDC(player, playerInvisKSKey, streak);
}
public long getInvisKillstreak(Player player) {
if(Killstreak.getInvisNinja() == null || !InvisNinja.isPlayerInvisible(player)) return getKillstreak(player);
return player.getPersistentDataContainer().getOrDefault(playerInvisKSKey, PersistentDataType.LONG, 0L);
final long realKS = this.getLongFromPDC(player, playerInvisKSKey);
if(Killstreak.getInvisNinja() == null || !InvisNinja.isPlayerInvisible(player)) {
long ks = this.getKillstreak(player);
if(ks > this.getBestKillstreak(player)) this.normaliseBestKillstreak(player);
this.setInvisKillstreak(player, ks);
return ks;
}
return realKS;
}
public long getKillstreak(OfflinePlayer player) {
return player.getPersistentDataContainer().getOrDefault(playerKillstreakKey, PersistentDataType.LONG, 0L);
return this.getLongFromPDC(player, playerKillstreakKey);
}
public long increaseKillstreak(Player player, long amount) {
@ -57,23 +76,35 @@ public class KillstreakManager {
}
public void resetKillstreak(Player player) {
setKillstreak(player, 0L);
this.setKillstreak(player, 0L);
}
private long getLongFromPDC(OfflinePlayer player, NamespacedKey key) {
return player.getPersistentDataContainer().getOrDefault(key, PersistentDataType.LONG, 0L);
}
private void setLongFromPDC(Player player, NamespacedKey key, long value) {
if(value < 0) return;
player.getPersistentDataContainer().set(key, PersistentDataType.LONG, value);
}
public boolean shouldAnnounceKillstreak(long killstreak, Player p) {
if(Killstreak.getInvisNinja() != null && InvisNinja.isPlayerInvisible(p)) return false;
return (killstreak >= 5 && killstreak % 5 == 0);
return killstreak >= 5 && killstreak % 5 == 0;
}
public int getColor(long killstreak) {
if(killstreak == 0) return 0xffffff;
else if(killstreak == 1) return 0xfbffa8; // washed out yellow
else if(killstreak < 5) return 0xfae92f; // yellow
else if(killstreak < 5) return 0xfae92f; // yellow
else if(killstreak < 10) return 0xe6aa1e; // orange orange
else if(killstreak < 15) return 0xe6711e; // darker orange
else if(killstreak < 20) return 0xf54320; // intense red
else if(killstreak < 30) return 0xde5291; // some fuckass pink
else if(killstreak < 30) return 0xde5291; // some fuckass pink
else return 0xde1ff0; // very intensive magenta
}
@ -81,4 +112,12 @@ public class KillstreakManager {
return Component.text("🔥", TextColor.color(0xff931f)) // 0xd18449
.append(Component.text(killstreak).color(TextColor.color(this.getColor(killstreak))).decoration(TextDecoration.BOLD, true));
}
public Component getBestKillstreakComponent(long bestKillstreak) {
return Component.text("🔥", TextColor.color(0x9c9c9c))
.append(Component.text(bestKillstreak).color(TextColor.color(0xababab)))
.decorations(Map.of(
TextDecoration.STRIKETHROUGH, State.TRUE,
TextDecoration.BOLD, State.TRUE
));
}
}

View file

@ -7,8 +7,12 @@ api-version: '1.21.11'
permissions:
ks.get:
default: true
ks.get.best:
default: true
ks.admin.get:
default: op
ks.admin.get.best:
default: op
ks.admin.set:
default: op
ks.admin.reset: