From ac83a4edb73a47abefad21a19e46c3d4d08fb1ca Mon Sep 17 00:00:00 2001 From: Patrick Miller Date: Tue, 5 May 2026 12:19:50 -0400 Subject: [PATCH] Fix EffKick, EffBan component support --- .../java/ch/njol/skript/effects/EffBan.java | 141 ---------------- .../java/ch/njol/skript/effects/EffKick.java | 70 -------- .../bukkit/entity/player/PlayerModule.java | 3 + .../player/elements/effects/EffBan.java | 154 ++++++++++++++++++ .../player/elements/effects/EffKick.java | 80 +++++++++ 5 files changed, 237 insertions(+), 211 deletions(-) delete mode 100644 src/main/java/ch/njol/skript/effects/EffBan.java delete mode 100644 src/main/java/ch/njol/skript/effects/EffKick.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/effects/EffBan.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/effects/EffKick.java diff --git a/src/main/java/ch/njol/skript/effects/EffBan.java b/src/main/java/ch/njol/skript/effects/EffBan.java deleted file mode 100644 index facf92c2ee4..00000000000 --- a/src/main/java/ch/njol/skript/effects/EffBan.java +++ /dev/null @@ -1,141 +0,0 @@ -package ch.njol.skript.effects; - -import ch.njol.skript.Skript; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Example; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.lang.Effect; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.lang.SyntaxStringBuilder; -import ch.njol.skript.util.Timespan; -import ch.njol.util.Kleenean; -import org.bukkit.BanList; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; - -import java.net.InetSocketAddress; -import java.util.Date; - -@Name("Ban") -@Description({"Bans or unbans a player or an IP address.", - "If a reason is given, it will be shown to the player when they try to join the server while banned.", - "A length of ban may also be given to apply a temporary ban. If it is absent for any reason, a permanent ban will be used instead.", - "We recommend that you test your scripts so that no accidental permanent bans are applied.", - "", - "Note that banning people does not kick them from the server.", - "You can optionally use 'and kick' or consider using the kick effect after applying a ban."}) -@Example("unban player") -@Example("ban \"127.0.0.1\"") -@Example("IP-ban the player because \"he is an idiot\"") -@Example("ban player due to \"inappropriate language\" for 2 days") -@Example("ban and kick player due to \"inappropriate language\" for 2 days") -@Since("1.4, 2.1.1 (ban reason), 2.5 (timespan), 2.9.0 (kick)") -public class EffBan extends Effect { - - static { - Skript.registerEffect(EffBan.class, - "ban [kick:and kick] %strings/offlineplayers% [(by reason of|because [of]|on account of|due to) %-string%] [for %-timespan%]", - "unban %strings/offlineplayers%", - "ban [kick:and kick] %players% by IP [(by reason of|because [of]|on account of|due to) %-string%] [for %-timespan%]", - "unban %players% by IP", - "IP(-| )ban [kick:and kick] %players% [(by reason of|because [of]|on account of|due to) %-string%] [for %-timespan%]", - "(IP(-| )unban|un[-]IP[-]ban) %players%"); - } - - @SuppressWarnings("null") - private Expression players; - @Nullable - private Expression reason; - @Nullable - private Expression expires; - - private boolean ban; - private boolean ipBan; - private boolean kick; - - @SuppressWarnings({"null", "unchecked"}) - @Override - public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parseResult) { - players = exprs[0]; - reason = exprs.length > 1 ? (Expression) exprs[1] : null; - expires = exprs.length > 1 ? (Expression) exprs[2] : null; - ban = matchedPattern % 2 == 0; - ipBan = matchedPattern >= 2; - kick = parseResult.hasTag("kick"); - return true; - } - - @SuppressWarnings("null") - @Override - protected void execute(final Event e) { - final String reason = this.reason != null ? this.reason.getSingle(e) : null; // don't check for null, just ignore an invalid reason - Timespan ts = this.expires != null ? this.expires.getSingle(e) : null; - final Date expires = ts != null ? new Date(System.currentTimeMillis() + ts.getAs(Timespan.TimePeriod.MILLISECOND)) : null; - final String source = "Skript ban effect"; - for (final Object o : players.getArray(e)) { - if (o instanceof Player) { - Player player = (Player) o; - if (ipBan) { - InetSocketAddress addr = player.getAddress(); - if (addr == null) - return; // Can't ban unknown IP - final String ip = addr.getAddress().getHostAddress(); - if (ban) - Bukkit.getBanList(BanList.Type.IP).addBan(ip, reason, expires, source); - else - Bukkit.getBanList(BanList.Type.IP).pardon(ip); - } else { - if (ban) - Bukkit.getBanList(BanList.Type.NAME).addBan(player.getName(), reason, expires, source); // FIXME [UUID] ban UUID - else - Bukkit.getBanList(BanList.Type.NAME).pardon(player.getName()); - } - if (kick) - player.kickPlayer(reason); - } else if (o instanceof OfflinePlayer) { - String name = ((OfflinePlayer) o).getName(); - if (name == null) - return; // Can't ban, name unknown - if (ban) - Bukkit.getBanList(BanList.Type.NAME).addBan(name, reason, expires, source); - else - Bukkit.getBanList(BanList.Type.NAME).pardon(name); - } else if (o instanceof String) { - final String s = (String) o; - if (ban) { - Bukkit.getBanList(BanList.Type.IP).addBan(s, reason, expires, source); - Bukkit.getBanList(BanList.Type.NAME).addBan(s, reason, expires, source); - } else { - Bukkit.getBanList(BanList.Type.IP).pardon(s); - Bukkit.getBanList(BanList.Type.NAME).pardon(s); - } - } else { - assert false; - } - } - } - - @Override - public String toString(@Nullable Event event, boolean debug) { - SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug); - - if (ipBan) - builder.append("IP"); - builder.append(ban ? "ban" : "unban"); - if (kick) - builder.append("and kick"); - builder.append(players); - if (reason != null) - builder.append("on account of", reason); - if (expires != null) - builder.append("for", expires); - - return builder.toString(); - } - -} diff --git a/src/main/java/ch/njol/skript/effects/EffKick.java b/src/main/java/ch/njol/skript/effects/EffKick.java deleted file mode 100644 index 14d3a7eaaea..00000000000 --- a/src/main/java/ch/njol/skript/effects/EffKick.java +++ /dev/null @@ -1,70 +0,0 @@ -package ch.njol.skript.effects; - -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerLoginEvent; -import org.bukkit.event.player.PlayerLoginEvent.Result; -import org.jetbrains.annotations.Nullable; - -import ch.njol.skript.Skript; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Example; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.lang.Effect; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.util.Kleenean; - -/** - * @author Peter Güttinger - */ -@Name("Kick") -@Description("Kicks a player from the server.") -@Example(""" - on place of TNT, lava, or obsidian: - kick the player due to "You may not place %block%!" - cancel the event - """) -@Since("1.0") -public class EffKick extends Effect { - static { - Skript.registerEffect(EffKick.class, "kick %players% [(by reason of|because [of]|on account of|due to) %-string%]"); - } - - @SuppressWarnings("null") - private Expression players; - @Nullable - private Expression reason; - - @SuppressWarnings({"unchecked", "null"}) - @Override - public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parseResult) { - players = (Expression) exprs[0]; - reason = (Expression) exprs[1]; - return true; - } - - @Override - public String toString(final @Nullable Event e, final boolean debug) { - return "kick " + players.toString(e, debug) + (reason != null ? " on account of " + reason.toString(e, debug) : ""); - } - - @Override - protected void execute(final Event e) { - final String r = reason != null ? reason.getSingle(e) : ""; - if (r == null) - return; - for (final Player p : players.getArray(e)) { - if (e instanceof PlayerLoginEvent && p.equals(((PlayerLoginEvent) e).getPlayer()) && !Delay.isDelayed(e)) { - ((PlayerLoginEvent) e).disallow(Result.KICK_OTHER, r); - } else if (e instanceof PlayerKickEvent && p.equals(((PlayerKickEvent) e).getPlayer()) && !Delay.isDelayed(e)) { - ((PlayerKickEvent) e).setLeaveMessage(r); - } else { - p.kickPlayer(r); - } - } - } - -} diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/player/PlayerModule.java b/src/main/java/org/skriptlang/skript/bukkit/entity/player/PlayerModule.java index 938a676b539..74bf611cbc9 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/entity/player/PlayerModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/player/PlayerModule.java @@ -6,6 +6,7 @@ import org.skriptlang.skript.addon.AddonModule; import org.skriptlang.skript.addon.HierarchicalAddonModule; import org.skriptlang.skript.addon.SkriptAddon; +import org.skriptlang.skript.bukkit.entity.player.elements.effects.*; import org.skriptlang.skript.bukkit.entity.player.elements.events.*; import org.skriptlang.skript.bukkit.entity.player.elements.expressions.*; import org.skriptlang.skript.bukkit.registration.BukkitSyntaxInfos; @@ -20,6 +21,8 @@ public PlayerModule(AddonModule parentModule) { @Override protected void loadSelf(SkriptAddon addon) { register(addon, + EffBan::register, + EffKick::register, ExprChatFormat::register, ExprChatMessage::register, ExprChatRecipients::register, diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/effects/EffBan.java b/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/effects/EffBan.java new file mode 100644 index 00000000000..45211043fb9 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/effects/EffBan.java @@ -0,0 +1,154 @@ +package org.skriptlang.skript.bukkit.entity.player.elements.effects; + +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.skript.util.Timespan; +import ch.njol.skript.util.Timespan.TimePeriod; +import ch.njol.util.Kleenean; +import net.kyori.adventure.text.Component; +import org.bukkit.BanList.Type; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.text.TextComponentParser; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; + +import java.net.InetSocketAddress; +import java.util.Date; + +@Name("Ban") +@Description({"Bans or unbans a player or an IP address.", + "If a reason is given, it will be shown to the player when they try to join the server while banned.", + "A length of ban may also be given to apply a temporary ban. If it is absent for any reason, a permanent ban will be used instead.", + "We recommend that you test your scripts so that no accidental permanent bans are applied.", + "", + "Note that banning people does not kick them from the server.", + "You can optionally use 'and kick' or consider using the kick effect after applying a ban."}) +@Example("unban player") +@Example("ban \"127.0.0.1\"") +@Example("IP-ban the player because \"he is an idiot\"") +@Example("ban player due to \"inappropriate language\" for 2 days") +@Example("ban and kick player due to \"inappropriate language\" for 2 days") +@Since("1.4, 2.1.1 (ban reason), 2.5 (timespan), 2.9.0 (kick)") +public class EffBan extends Effect { + + private static final String SKRIPT_BAN_SOURCE = "Skript ban effect"; + + public static void register(SyntaxRegistry syntaxRegistry) { + syntaxRegistry.register(SyntaxRegistry.EFFECT, SyntaxInfo.builder(EffBan.class) + .supplier(EffBan::new) + .addPatterns("ban [kick:and kick] %strings/offlineplayers% [(by reason of|because [of]|on account of|due to) %-textcomponent%] [for %-timespan%]", + "unban %strings/offlineplayers%", + "ban [kick:and kick] %players% by IP [(by reason of|because [of]|on account of|due to) %-textcomponent%] [for %-timespan%]", + "unban %players% by IP", + "IP(-| )ban [kick:and kick] %players% [(by reason of|because [of]|on account of|due to) %-textcomponent%] [for %-timespan%]", + "(IP(-| )unban|un[-]IP[-]ban) %players%") + .build()); + } + + private Expression players; + private @Nullable Expression reason; + private @Nullable Expression expires; + + private boolean ban; + private boolean ipBan; + private boolean kick; + + @Override + @SuppressWarnings("unchecked") + public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parseResult) { + players = exprs[0]; + reason = exprs.length > 1 ? (Expression) exprs[1] : null; + expires = exprs.length > 1 ? (Expression) exprs[2] : null; + ban = matchedPattern % 2 == 0; + ipBan = matchedPattern >= 2; + kick = parseResult.hasTag("kick"); + return true; + } + + @Override + protected void execute(Event event) { + Component reason = this.reason == null ? null : this.reason.getSingle(event); // don't check for null, just ignore an invalid reason + Timespan duration = this.expires == null ? null : this.expires.getSingle(event); + Date expires = duration == null ? null : new Date(System.currentTimeMillis() + duration.getAs(TimePeriod.MILLISECOND)); + for (Object object : players.getArray(event)) { + switch (object) { + case Player player -> { + if (ipBan) { + InetSocketAddress address = player.getAddress(); + if (address == null) { // Can't ban unknown IP + return; + } + String ip = address.getAddress().getHostAddress(); + var banList = Bukkit.getBanList(Type.IP); + if (ban) { + String legacyReason = TextComponentParser.instance().toLegacyString(reason); + banList.addBan(ip, legacyReason, expires, SKRIPT_BAN_SOURCE); + } else { + banList.pardon(ip); + } + } else { + var banList = Bukkit.getBanList(Type.NAME); + if (ban) { + String legacyReason = TextComponentParser.instance().toLegacyString(reason); + banList.addBan(player.getName(), legacyReason, expires, SKRIPT_BAN_SOURCE); // FIXME [UUID] ban UUID + } else { + banList.pardon(player.getName()); + } + } + if (kick) { + player.kick(reason); + } + } + case OfflinePlayer offlinePlayer -> { + String name = offlinePlayer.getName(); + if (name == null) { // Can't ban, name unknown + return; + } + var banList = Bukkit.getBanList(Type.NAME); + if (ban) { + String legacyReason = TextComponentParser.instance().toLegacyString(reason); + banList.addBan(name, legacyReason, expires, SKRIPT_BAN_SOURCE); + } else { + banList.pardon(name); + } + } + case String ip -> { + var ipBanList = Bukkit.getBanList(Type.IP); + var nameBanList = Bukkit.getBanList(Type.NAME); + if (ban) { + String legacyReason = TextComponentParser.instance().toLegacyString(reason); + ipBanList.addBan(ip, legacyReason, expires, SKRIPT_BAN_SOURCE); + nameBanList.addBan(ip, legacyReason, expires, SKRIPT_BAN_SOURCE); + } else { + ipBanList.pardon(ip); + nameBanList.pardon(ip); + } + } + default -> throw new IllegalStateException("Unexpected value: " + object); + } + } + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return new SyntaxStringBuilder(event, debug) + .appendIf(ipBan, "IP") + .append(ban ? "ban" : "unban") + .appendIf(kick, "and kick") + .append(players) + .appendIf(reason != null, "on account of", reason) + .appendIf(expires != null, "for", expires) + .toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/effects/EffKick.java b/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/effects/EffKick.java new file mode 100644 index 00000000000..8e85ced9449 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/effects/EffKick.java @@ -0,0 +1,80 @@ +package org.skriptlang.skript.bukkit.entity.player.elements.effects; + +import ch.njol.skript.effects.Delay; +import ch.njol.skript.lang.SyntaxStringBuilder; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerLoginEvent; +import org.jetbrains.annotations.Nullable; + +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; + +@Name("Kick") +@Description("Kicks a player from the server.") +@Example(""" + on place of TNT, lava, or obsidian: + kick the player due to "You may not place %block%!" + cancel the event + """) +@Since("1.0") +public class EffKick extends Effect { + + public static void register(SyntaxRegistry syntaxRegistry) { + syntaxRegistry.register(SyntaxRegistry.EFFECT, SyntaxInfo.builder(EffKick.class) + .supplier(EffKick::new) + .addPattern("kick %players% [(by reason of|because [of]|on account of|due to) %-textcomponent%]") + .build()); + } + + private Expression players; + private @Nullable Expression reason; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + players = (Expression) exprs[0]; + //noinspection unchecked + reason = (Expression) exprs[1]; + return true; + } + + @Override + protected void execute(Event event) { + Component reason = this.reason == null ? Component.empty() : this.reason.getSingle(event); + if (reason == null) { + return; + } + for (Player player : players.getArray(event)) { + if (!Delay.isDelayed(event)) { // handle event specific cases + if (event instanceof PlayerLoginEvent loginEvent && player.equals(loginEvent.getPlayer())) { + loginEvent.disallow(PlayerLoginEvent.Result.KICK_OTHER, reason); + return; + } else if (event instanceof PlayerKickEvent kickEvent && player.equals(kickEvent.getPlayer())) { + kickEvent.leaveMessage(reason); + return; + } + } + player.kick(reason); + } + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return new SyntaxStringBuilder(event, debug) + .append("kick", players) + .appendIf(reason != null, "on account of", reason) + .toString(); + } + +}