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();
+ }
+
+}