Skip to content

Commit 03bb3ae

Browse files
committed
Add /kick and /ban commands
1 parent 85e3238 commit 03bb3ae

7 files changed

Lines changed: 220 additions & 3 deletions

File tree

src/main/java/dev/xdpxi/swiftmc/Main.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ static void server() throws Exception {
214214
MinecraftServer.getCommandManager().register(new Teleport());
215215
MinecraftServer.getCommandManager().register(new Op());
216216
MinecraftServer.getCommandManager().register(new Deop());
217+
MinecraftServer.getCommandManager().register(new Kick());
218+
MinecraftServer.getCommandManager().register(new Ban());
219+
MinecraftServer.getCommandManager().register(new Unban());
217220
Log.info("Commands registered.");
218221

219222
// Minestom PVP Events
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package dev.xdpxi.swiftmc.commands;
2+
3+
import dev.xdpxi.swiftmc.player.PlayerDataManager;
4+
import dev.xdpxi.swiftmc.utils.Log;
5+
import net.kyori.adventure.text.Component;
6+
import net.kyori.adventure.text.format.NamedTextColor;
7+
import net.minestom.server.MinecraftServer;
8+
import net.minestom.server.command.ConsoleSender;
9+
import net.minestom.server.command.builder.Command;
10+
import net.minestom.server.command.builder.arguments.ArgumentType;
11+
import net.minestom.server.command.builder.suggestion.SuggestionEntry;
12+
import net.minestom.server.entity.Player;
13+
14+
public class Ban extends Command {
15+
16+
public Ban() {
17+
super("ban");
18+
19+
var nameArg = ArgumentType.Word("player")
20+
.setSuggestionCallback((sender, context, suggestion) -> {
21+
for (Player online : MinecraftServer.getConnectionManager().getOnlinePlayers()) {
22+
suggestion.addEntry(new SuggestionEntry(online.getUsername()));
23+
}
24+
});
25+
var reasonArg = ArgumentType.StringArray("reason");
26+
27+
setCondition((sender, cmd) ->
28+
sender instanceof ConsoleSender || (sender instanceof Player p && p.getPermissionLevel() >= 4)
29+
);
30+
31+
setDefaultExecutor((sender, context) ->
32+
sender.sendMessage(Component.text("Usage: /ban <player> [reason]", NamedTextColor.RED))
33+
);
34+
35+
// /ban <player>
36+
addSyntax((sender, context) -> {
37+
String target = context.get(nameArg);
38+
executeBan(sender, target, null);
39+
}, nameArg);
40+
41+
// /ban <player> <reason>
42+
addSyntax((sender, context) -> {
43+
String target = context.get(nameArg);
44+
String reason = String.join(" ", context.get(reasonArg));
45+
executeBan(sender, target, reason);
46+
}, nameArg, reasonArg);
47+
}
48+
49+
private static void executeBan(net.minestom.server.command.CommandSender sender, String target, String reason) {
50+
PlayerDataManager.setBan(target, true, reason).thenAccept(found -> {
51+
if (found) {
52+
sender.sendMessage(Component.text("Banned " + target + ".", NamedTextColor.GREEN));
53+
Log.info((sender instanceof Player p ? p.getUsername() : "Console") + " banned " + target
54+
+ (reason != null && !reason.isBlank() ? ": " + reason : ""));
55+
} else {
56+
sender.sendMessage(Component.text("Player '" + target + "' has never joined the server.", NamedTextColor.RED));
57+
}
58+
});
59+
}
60+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package dev.xdpxi.swiftmc.commands;
2+
3+
import dev.xdpxi.swiftmc.utils.Log;
4+
import net.kyori.adventure.text.Component;
5+
import net.kyori.adventure.text.format.NamedTextColor;
6+
import net.minestom.server.MinecraftServer;
7+
import net.minestom.server.command.ConsoleSender;
8+
import net.minestom.server.command.builder.Command;
9+
import net.minestom.server.command.builder.arguments.ArgumentType;
10+
import net.minestom.server.command.builder.suggestion.SuggestionEntry;
11+
import net.minestom.server.entity.Player;
12+
13+
public class Kick extends Command {
14+
15+
public Kick() {
16+
super("kick");
17+
18+
var nameArg = ArgumentType.Word("player")
19+
.setSuggestionCallback((sender, context, suggestion) -> {
20+
for (Player online : MinecraftServer.getConnectionManager().getOnlinePlayers()) {
21+
suggestion.addEntry(new SuggestionEntry(online.getUsername()));
22+
}
23+
});
24+
var reasonArg = ArgumentType.StringArray("reason");
25+
26+
setCondition((sender, cmd) ->
27+
sender instanceof ConsoleSender || (sender instanceof Player p && p.getPermissionLevel() >= 2)
28+
);
29+
30+
setDefaultExecutor((sender, context) ->
31+
sender.sendMessage(Component.text("Usage: /kick <player> [reason]", NamedTextColor.RED))
32+
);
33+
34+
// /kick <player>
35+
addSyntax((sender, context) -> {
36+
String target = context.get(nameArg);
37+
kickPlayer(sender, target, null);
38+
}, nameArg);
39+
40+
// /kick <player> <reason>
41+
addSyntax((sender, context) -> {
42+
String target = context.get(nameArg);
43+
String reason = String.join(" ", context.get(reasonArg));
44+
kickPlayer(sender, target, reason);
45+
}, nameArg, reasonArg);
46+
}
47+
48+
private static void kickPlayer(net.minestom.server.command.CommandSender sender, String target, String reason) {
49+
for (Player online : MinecraftServer.getConnectionManager().getOnlinePlayers()) {
50+
if (online.getUsername().equalsIgnoreCase(target)) {
51+
String msg = reason != null && !reason.isBlank()
52+
? "Kicked by an operator: " + reason
53+
: "Kicked by an operator.";
54+
online.kick(Component.text(msg, NamedTextColor.RED));
55+
sender.sendMessage(Component.text("Kicked " + online.getUsername() + ".", NamedTextColor.GREEN));
56+
Log.info((sender instanceof Player p ? p.getUsername() : "Console") + " kicked " + online.getUsername()
57+
+ (reason != null && !reason.isBlank() ? ": " + reason : ""));
58+
return;
59+
}
60+
}
61+
sender.sendMessage(Component.text("Player '" + target + "' is not online.", NamedTextColor.RED));
62+
}
63+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package dev.xdpxi.swiftmc.commands;
2+
3+
import dev.xdpxi.swiftmc.player.PlayerDataManager;
4+
import dev.xdpxi.swiftmc.utils.Log;
5+
import net.kyori.adventure.text.Component;
6+
import net.kyori.adventure.text.format.NamedTextColor;
7+
import net.minestom.server.command.ConsoleSender;
8+
import net.minestom.server.command.builder.Command;
9+
import net.minestom.server.command.builder.arguments.ArgumentType;
10+
import net.minestom.server.entity.Player;
11+
12+
public class Unban extends Command {
13+
14+
public Unban() {
15+
super("unban", "pardon");
16+
17+
var nameArg = ArgumentType.Word("player");
18+
19+
setCondition((sender, cmd) ->
20+
sender instanceof ConsoleSender || (sender instanceof Player p && p.getPermissionLevel() >= 4)
21+
);
22+
23+
setDefaultExecutor((sender, context) ->
24+
sender.sendMessage(Component.text("Usage: /unban <player>", NamedTextColor.RED))
25+
);
26+
27+
addSyntax((sender, context) -> {
28+
String target = context.get(nameArg);
29+
PlayerDataManager.setBan(target, false, "").thenAccept(found -> {
30+
if (found) {
31+
sender.sendMessage(Component.text("Unbanned " + target + ".", NamedTextColor.GREEN));
32+
Log.info((sender instanceof Player p ? p.getUsername() : "Console") + " unbanned " + target);
33+
} else {
34+
sender.sendMessage(Component.text("Player '" + target + "' has never joined the server.", NamedTextColor.RED));
35+
}
36+
});
37+
}, nameArg);
38+
}
39+
}

src/main/java/dev/xdpxi/swiftmc/events/AsyncPlayerConfigurationEvent.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package dev.xdpxi.swiftmc.events;
22

3+
import dev.xdpxi.swiftmc.player.PlayerData;
4+
import dev.xdpxi.swiftmc.player.PlayerDataManager;
5+
import net.kyori.adventure.text.Component;
6+
import net.kyori.adventure.text.format.NamedTextColor;
37
import net.minestom.server.coordinate.Pos;
48
import net.minestom.server.entity.Player;
59
import net.minestom.server.event.GlobalEventHandler;
@@ -13,12 +17,21 @@ public static void addListener(
1317
InstanceContainer instanceContainer
1418
) {
1519
globalEventHandler.addListener(
16-
net.minestom.server.event.player
17-
.AsyncPlayerConfigurationEvent.class,
20+
net.minestom.server.event.player.AsyncPlayerConfigurationEvent.class,
1821
event -> {
1922
final Player player = event.getPlayer();
20-
event.setSpawningInstance(instanceContainer);
2123
player.setRespawnPoint(new Pos(0, 64, 0));
24+
25+
PlayerData data = PlayerDataManager.loadDataByUuid(player.getUuid()).join();
26+
if (data != null && data.banned) {
27+
String msg = data.banReason != null && !data.banReason.isBlank()
28+
? "You are banned: " + data.banReason
29+
: "You are banned from this server.";
30+
player.kick(Component.text(msg, NamedTextColor.RED));
31+
return;
32+
}
33+
34+
event.setSpawningInstance(instanceContainer);
2235
}
2336
);
2437
}

src/main/java/dev/xdpxi/swiftmc/player/PlayerData.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public class PlayerData {
1818
public float yaw, pitch;
1919
public GameMode gameMode;
2020
public boolean op = false;
21+
public boolean banned = false;
22+
public String banReason = "";
2123

2224
public PlayerData() {
2325
}

src/main/java/dev/xdpxi/swiftmc/player/PlayerDataManager.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,43 @@ public static void loadPlayer(@NonNull Player player) {
8585
}, IO_EXECUTOR);
8686
}
8787

88+
@Contract("_, _, _ -> new")
89+
public static @NonNull CompletableFuture<Boolean> setBan(String username, boolean banned, String reason) {
90+
return CompletableFuture.supplyAsync(() -> {
91+
try {
92+
if (!Files.exists(PLAYER_FOLDER)) return false;
93+
for (Path file : Files.newDirectoryStream(PLAYER_FOLDER, "*.json")) {
94+
String json = Files.readString(file);
95+
PlayerData data = GSON.fromJson(json, PlayerData.class);
96+
if (data != null && username.equalsIgnoreCase(data.username)) {
97+
data.banned = banned;
98+
data.banReason = reason == null ? "" : reason;
99+
Files.writeString(file, GSON.toJson(data));
100+
if (banned) {
101+
for (Player online : MinecraftServer.getConnectionManager().getOnlinePlayers()) {
102+
if (online.getUsername().equalsIgnoreCase(username)) {
103+
String msg = reason != null && !reason.isBlank()
104+
? "You have been banned: " + reason
105+
: "You have been banned from this server.";
106+
online.kick(msg);
107+
break;
108+
}
109+
}
110+
}
111+
return true;
112+
}
113+
}
114+
} catch (IOException e) {
115+
e.printStackTrace();
116+
}
117+
return false;
118+
}, IO_EXECUTOR);
119+
}
120+
121+
public static @NonNull CompletableFuture<PlayerData> loadDataByUuid(@NonNull UUID uuid) {
122+
return loadDataAsync(uuid);
123+
}
124+
88125
@Contract("_, _ -> new")
89126
public static @NonNull CompletableFuture<Boolean> setOp(String username, boolean op) {
90127
return CompletableFuture.supplyAsync(() -> {

0 commit comments

Comments
 (0)