Command related patches

This commit is contained in:
AlphaKR93
2025-02-24 01:53:56 +09:00
parent 637b0ef8cb
commit 55fbffae38
24 changed files with 1029 additions and 402 deletions

View File

@@ -0,0 +1,291 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlphaKR93 <dev@alpha93.kr>
Date: Fri, 3 Nov 2023 00:11:50 +0900
Subject: [PATCH] Plazma Configurations
diff --git a/src/main/java/org/plazmamc/plazma/commands/Commands.java b/src/main/java/org/plazmamc/plazma/commands/Commands.java
new file mode 100644
index 0000000000000000000000000000000000000000..4497d8f8a52db0fc89ce27168b54657d172b1445
--- /dev/null
+++ b/src/main/java/org/plazmamc/plazma/commands/Commands.java
@@ -0,0 +1,23 @@
+package org.plazmamc.plazma.commands;
+
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.command.Command;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+import org.plazmamc.plazma.commands.plazma.PlazmaCommand;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@DefaultQualifier(NonNull.class)
+public class Commands {
+
+ private static final Map<String, Command> COMMANDS = new HashMap<>() {{
+ put("plazma", new PlazmaCommand("plazma"));
+ }};
+
+ public static void register(final MinecraftServer server) {
+ COMMANDS.forEach((s, command) -> server.server.getCommandMap().register(s, "Plazma", command));
+ }
+
+}
diff --git a/src/main/java/org/plazmamc/plazma/commands/PlazmaSubCommand.java b/src/main/java/org/plazmamc/plazma/commands/PlazmaSubCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..e25ba7935e2743aab5c1334c6582459556ec643a
--- /dev/null
+++ b/src/main/java/org/plazmamc/plazma/commands/PlazmaSubCommand.java
@@ -0,0 +1,19 @@
+package org.plazmamc.plazma.commands;
+
+import org.bukkit.command.CommandSender;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+import java.util.Collections;
+import java.util.List;
+
+@DefaultQualifier(NonNull.class)
+public interface PlazmaSubCommand {
+
+ boolean execute(final CommandSender sender, final String subCommand, final String[] args);
+
+ default List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
+ return Collections.emptyList();
+ }
+
+}
diff --git a/src/main/java/org/plazmamc/plazma/commands/plazma/PlazmaCommand.java b/src/main/java/org/plazmamc/plazma/commands/plazma/PlazmaCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..1628bee2fb106ad149cad95fb5e3d1100448c697
--- /dev/null
+++ b/src/main/java/org/plazmamc/plazma/commands/plazma/PlazmaCommand.java
@@ -0,0 +1,120 @@
+package org.plazmamc.plazma.commands.plazma;
+
+import io.papermc.paper.command.CommandUtil;
+import it.unimi.dsi.fastutil.Pair;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.minecraft.Util;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.permissions.Permission;
+import org.bukkit.permissions.PermissionDefault;
+import org.bukkit.plugin.PluginManager;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+import org.plazmamc.plazma.commands.PlazmaSubCommand;
+import org.plazmamc.plazma.commands.plazma.subcommand.ReloadCommand;
+import org.plazmamc.plazma.commands.plazma.subcommand.VersionCommand;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static net.kyori.adventure.text.Component.text;
+
+@DefaultQualifier(NonNull.class)
+public class PlazmaCommand extends Command {
+
+ private static final Map<String, PlazmaSubCommand> SUB_COMMANDS = Util.make(() -> {
+ final Map<Set<String>, PlazmaSubCommand> commands = new HashMap<>() {{
+ put(Set.of("reload"), new ReloadCommand());
+ put(Set.of("version"), new VersionCommand());
+ }};
+
+ return commands.entrySet().stream()
+ .flatMap(entry -> entry.getKey().stream().map(key -> Map.entry(key, entry.getValue())))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ });
+
+ private static final Map<String, String> ALIASES = Util.make(() -> {
+ final Map<String, Set<String>> aliases = new HashMap<>() {{
+ put("reload", Set.of("rl"));
+ put("version", Set.of("ver"));
+ }};
+
+ return aliases.entrySet().stream()
+ .flatMap(entry -> entry.getValue().stream().map(s -> Map.entry(s, entry.getKey())))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ });
+
+ public PlazmaCommand(final String name) {
+ super(name);
+
+ final PluginManager pluginManager = Bukkit.getServer().getPluginManager();
+
+ final List<String> permissions = new ArrayList<>();
+ permissions.add("bukkit.command.plazma");
+ permissions.addAll(SUB_COMMANDS.keySet().stream().map(s -> "bukkit.command.plazma." + s).toList());
+
+ this.description = "Plazma related commands";
+ this.usageMessage = String.format("/plazma [%s]", String.join("|", SUB_COMMANDS.keySet()));
+ this.setPermission(String.join(";", permissions));
+
+ permissions.forEach(perm -> pluginManager.addPermission(new Permission(perm, PermissionDefault.OP)));
+ }
+
+ @Override
+ public boolean execute(final CommandSender sender, final String commandLabel, final String[] args) {
+ if (!testPermission(sender)) return true;
+
+ if (args.length == 0) {
+ sender.sendMessage(text("Usage: " + this.usageMessage, NamedTextColor.RED));
+ return false;
+ }
+
+ final @Nullable Pair<String, PlazmaSubCommand> subCommand = resolveSubCommand(args[0]);
+
+ if (subCommand == null) {
+ sender.sendMessage(text("Usage: " + this.usageMessage, NamedTextColor.RED));
+ return false;
+ }
+
+ if (!testPermission(sender, subCommand.first())) return true;
+
+ final String[] choppedArgs = Arrays.copyOfRange(args, 1, args.length);
+ return subCommand.second().execute(sender, subCommand.first(), choppedArgs);
+ }
+
+ @Override
+ public List<String> tabComplete(final CommandSender sender, final String aliases, final String[] args) throws IllegalArgumentException {
+ if (args.length <= 1) return CommandUtil.getListMatchingLast(sender, args, SUB_COMMANDS.keySet());
+
+ final @Nullable Pair<String, PlazmaSubCommand> subCommand = resolveSubCommand(args[0]);
+
+ if (subCommand != null) return subCommand.second().tabComplete(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length));
+ return Collections.emptyList();
+ }
+
+ private static boolean testPermission(final CommandSender sender, final String permission) {
+ if (sender.hasPermission("bukkit.command.plazma." + permission) || sender.hasPermission("bukkit.command.plazma")) return true;
+ sender.sendMessage(Bukkit.permissionMessage());
+ return false;
+ }
+
+ private static @Nullable Pair<String, PlazmaSubCommand> resolveSubCommand(String label) {
+ label = label.toLowerCase(Locale.ENGLISH);
+ @Nullable PlazmaSubCommand subCommand = SUB_COMMANDS.get(label);
+
+ if (subCommand == null) {
+ final @Nullable String command = ALIASES.get(label);
+ if (command != null) {
+ label = command;
+ subCommand = SUB_COMMANDS.get(label);
+ }
+ }
+
+ if (subCommand != null) return Pair.of(label, subCommand);
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/plazmamc/plazma/commands/plazma/subcommand/ReloadCommand.java b/src/main/java/org/plazmamc/plazma/commands/plazma/subcommand/ReloadCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c83926923f50fb4da1a83dc91614c20a831555f
--- /dev/null
+++ b/src/main/java/org/plazmamc/plazma/commands/plazma/subcommand/ReloadCommand.java
@@ -0,0 +1,34 @@
+package org.plazmamc.plazma.commands.plazma.subcommand;
+
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.CraftServer;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+import org.plazmamc.plazma.commands.PlazmaSubCommand;
+
+import static net.kyori.adventure.text.Component.text;
+
+@DefaultQualifier(NonNull.class)
+public class ReloadCommand implements PlazmaSubCommand {
+
+ @Override
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
+ this.reload(sender);
+ return true;
+ }
+
+ private void reload(final CommandSender sender) {
+ Command.broadcastCommandMessage(sender, text("Please note that this command is not supported and may cause issues.", NamedTextColor.RED));
+ Command.broadcastCommandMessage(sender, text("If you encounter any issues please use the /stop command to restart your server.", NamedTextColor.RED));
+
+ MinecraftServer server = ((CraftServer) sender.getServer()).getServer();
+ server.plazmaConfigurations.reloadConfigs(server);
+ server.server.reloadCount++;
+
+ Command.broadcastCommandMessage(sender, text("Successfully reloaded Plazma configuration files.", NamedTextColor.GREEN));
+ }
+
+}
diff --git a/src/main/java/org/plazmamc/plazma/commands/plazma/subcommand/VersionCommand.java b/src/main/java/org/plazmamc/plazma/commands/plazma/subcommand/VersionCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6664ba0fce55f5cfa0c8d3051dc8c2be0fd0703
--- /dev/null
+++ b/src/main/java/org/plazmamc/plazma/commands/plazma/subcommand/VersionCommand.java
@@ -0,0 +1,21 @@
+package org.plazmamc.plazma.commands.plazma.subcommand;
+
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+import org.plazmamc.plazma.commands.PlazmaSubCommand;
+
+@DefaultQualifier(NonNull.class)
+public class VersionCommand implements PlazmaSubCommand {
+
+ @Override
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
+ final @Nullable Command ver = MinecraftServer.getServer().server.getCommandMap().getCommand("version");
+ if (ver != null) return ver.execute(sender, "plazma", new String[0]);
+ return false;
+ }
+
+}
diff --git a/src/test/java/org/bukkit/support/DummyServerHelper.java b/src/test/java/org/bukkit/support/DummyServerHelper.java
index 309d371247adcddf0a1b370cc5faff3e6e01cb0f..285a90ff5cdc8cb28fafd4ea3dae306ae5b899c9 100644
--- a/src/test/java/org/bukkit/support/DummyServerHelper.java
+++ b/src/test/java/org/bukkit/support/DummyServerHelper.java
@@ -92,6 +92,7 @@ public final class DummyServerHelper {
// Paper end - testing additions
io.papermc.paper.configuration.GlobalConfigTestingBase.setupGlobalConfigForTest(); // Paper - configuration files - setup global configuration test base
+ org.plazmamc.plazma.configurations.GlobalConfigurationTestingBase.setupGlobalConfigForTest(); // Plazma - Configurable Plazma
// Paper start - add test for recipe conversion
when(instance.recipeIterator()).thenAnswer(ignored ->
diff --git a/src/test/java/org/plazmamc/plazma/configurations/GlobalConfigurationTestingBase.java b/src/test/java/org/plazmamc/plazma/configurations/GlobalConfigurationTestingBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..c63942e2dc00ed6d6b4119f418bdaa5a64b4c0fe
--- /dev/null
+++ b/src/test/java/org/plazmamc/plazma/configurations/GlobalConfigurationTestingBase.java
@@ -0,0 +1,20 @@
+package org.plazmamc.plazma.configurations;
+
+import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.serialize.SerializationException;
+
+public class GlobalConfigurationTestingBase {
+
+ public static void setupGlobalConfigForTest() {
+ if (GlobalConfiguration.get() == null) {
+ ConfigurationNode node = PlazmaConfigurations.createForTesting();
+ try {
+ GlobalConfiguration globalConfiguration = node.require(GlobalConfiguration.class);
+ GlobalConfiguration.set(globalConfiguration);
+ } catch (SerializationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+}

View File

@@ -0,0 +1,125 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlphaKR93 <dev@alpha93.kr>
Date: Wed, 25 Dec 2024 15:08:03 +0900
Subject: [PATCH] Add option to set player can bypass limit
diff --git a/src/main/java/net/minecraft/server/commands/OpCommand.java b/src/main/java/net/minecraft/server/commands/OpCommand.java
index e7b444a10b244828827b3c66c53465206ea8e0ec..af455e7f1c22fda87dbc5b487b757d046dcc2d49 100644
--- a/src/main/java/net/minecraft/server/commands/OpCommand.java
+++ b/src/main/java/net/minecraft/server/commands/OpCommand.java
@@ -34,20 +34,41 @@ public class OpCommand {
}
)
.executes(context -> opPlayers(context.getSource(), GameProfileArgument.getGameProfiles(context, "targets")))
+ // Plazma start - Add an option to set player can bypass limit
+ .then(
+ Commands.argument("permissionLevel", com.mojang.brigadier.arguments.IntegerArgumentType.integer(0, 4))
+ .executes(context ->
+ opPlayers(context.getSource(), GameProfileArgument.getGameProfiles(context, "targets"), com.mojang.brigadier.arguments.IntegerArgumentType.getInteger(context, "permissionLevel"), false)
+ )
+ .then(
+ Commands.argument("bypassPlayerLimit", com.mojang.brigadier.arguments.BoolArgumentType.bool())
+ .executes(context ->
+ opPlayers(context.getSource(), GameProfileArgument.getGameProfiles(context, "targets"), com.mojang.brigadier.arguments.IntegerArgumentType.getInteger(context, "permissionLevel"), com.mojang.brigadier.arguments.BoolArgumentType.getBool(context, "bypassPlayerLimit"))
+ )
+ )
+ )
+ // Plazma end - Add an option to set player can bypass limit
)
);
}
-
private static int opPlayers(CommandSourceStack source, Collection<GameProfile> targets) throws CommandSyntaxException {
+ // Plazma start - Add an option to set player can bypass limit
+ return opPlayers(source, targets, source.getServer().getOperatorUserPermissionLevel(), false);
+ }
+
+ private static int opPlayers(final CommandSourceStack source, final Collection<GameProfile> targets, final int permissionLevel, final boolean bypassPlayerLimit) throws CommandSyntaxException {
+ // Plazma end - Add an option to set player can bypass limit
PlayerList playerList = source.getServer().getPlayerList();
int i = 0;
for (GameProfile gameProfile : targets) {
- if (!playerList.isOp(gameProfile)) {
- playerList.op(gameProfile);
- i++;
- source.sendSuccess(() -> Component.translatable("commands.op.success", gameProfile.getName()), true); // Paper - fixes MC-253721
- }
+ // Plazma start - Add an option to set player can bypass limit
+ if (playerList.isOp(gameProfile) && playerList.canBypassPlayerLimit(gameProfile) == bypassPlayerLimit && playerList.getPermissionLevel(gameProfile) == permissionLevel) continue;
+
+ playerList.op(gameProfile, permissionLevel, bypassPlayerLimit);
+ source.sendSuccess(() -> Component.translatable("commands.op.success", gameProfile.getName()), true); // Paper - fixes MC-253721
+ i++;
+ // Plazma end - Add an option to set player can bypass limit
}
if (i == 0) {
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java b/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java
index 20c531f11b310dab0a867e589c769393ed835df5..7d9358f3e287d1f05d799b1c8f59509e6ede8581 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java
@@ -122,4 +122,11 @@ public class DedicatedPlayerList extends PlayerList {
public boolean canBypassPlayerLimit(GameProfile profile) {
return this.getOps().canBypassPlayerLimit(profile);
}
+
+ // Plazma start - Add an option to set player can bypass limit
+ @Override
+ public int getPermissionLevel(GameProfile profile) {
+ return this.getOps().getLevel(profile);
+ }
+ // Plazma end - Add an option to set player can bypass limit
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 8ab6df63d9a22ac76b2ba14bc8fef318e65484c8..81bae0453e09454c43d547c48de2f201a5e41023 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -1085,8 +1085,14 @@ public abstract class PlayerList {
return this.ipBans;
}
+ // Plazma start - Add an option to set player can bypass limit
public void op(GameProfile profile) {
- this.ops.add(new ServerOpListEntry(profile, this.server.getOperatorUserPermissionLevel(), this.ops.canBypassPlayerLimit(profile)));
+ this.op(profile, this.server.getOperatorUserPermissionLevel(), this.ops.canBypassPlayerLimit(profile));
+ }
+
+ public void op(final GameProfile profile, final int permissionLevel, final boolean bypassPlayerLimit) {
+ // Plazma end - Add an option to set player can bypass limit
+ this.ops.add(new ServerOpListEntry(profile, permissionLevel, bypassPlayerLimit));
ServerPlayer entityplayer = this.getPlayer(profile.getId());
if (entityplayer != null) {
@@ -1530,6 +1536,12 @@ public abstract class PlayerList {
return false;
}
+ // Plazma start - Add an option to set player can bypass limit
+ public int getPermissionLevel(GameProfile profile) {
+ return 0;
+ }
+ // Plazma end - Add an option to set player can bypass limit
+
public void reloadResources() {
// Paper start - API for updating recipes on clients
this.reloadAdvancementData();
diff --git a/src/main/java/net/minecraft/server/players/ServerOpList.java b/src/main/java/net/minecraft/server/players/ServerOpList.java
index a1c9686043b5a8c5cb1614b46e10484000c920ae..c2f597375003065434f1559959783a5b7de838f1 100644
--- a/src/main/java/net/minecraft/server/players/ServerOpList.java
+++ b/src/main/java/net/minecraft/server/players/ServerOpList.java
@@ -20,6 +20,13 @@ public class ServerOpList extends StoredUserList<GameProfile, ServerOpListEntry>
return this.getEntries().stream().map(StoredUserEntry::getUser).filter(Objects::nonNull).map(GameProfile::getName).toArray(String[]::new);
}
+ // Plazma start - Add an option to set player can bypass limit
+ public int getLevel(GameProfile profile) {
+ ServerOpListEntry serverOpListEntry = this.get(profile);
+ return serverOpListEntry != null ? serverOpListEntry.getLevel() : 0;
+ }
+ // Plazma end - Add an option to set player can bypass limit
+
public boolean canBypassPlayerLimit(GameProfile profile) {
ServerOpListEntry serverOpListEntry = this.get(profile);
return serverOpListEntry != null && serverOpListEntry.getBypassesPlayerLimit();

View File

@@ -0,0 +1,122 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlphaKR93 <dev@alpha93.kr>
Date: Wed, 25 Dec 2024 19:07:19 +0900
Subject: [PATCH] Add heal command
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
index c416b1eaf27699de59aaa6b352ff1aa991d3f660..90ecfc550324521a7aece274bab330f8dc2de3f3 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -180,6 +180,7 @@ public class Commands {
org.purpurmc.purpur.command.CompassCommand.register(this.dispatcher); // Purpur
org.purpurmc.purpur.command.RamBarCommand.register(this.dispatcher); // Purpur - Implement ram and rambar commands
org.purpurmc.purpur.command.RamCommand.register(this.dispatcher); // Purpur - Implement ram and rambar commands
+ org.plazmamc.plazma.commands.HealCommand.register(this.dispatcher); // Plazma - Add heal command
}
if (environment.includeIntegrated) {
diff --git a/src/main/java/org/plazmamc/plazma/commands/HealCommand.java b/src/main/java/org/plazmamc/plazma/commands/HealCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..b10725af7ec4433e98557cfbafb563822cd4f908
--- /dev/null
+++ b/src/main/java/org/plazmamc/plazma/commands/HealCommand.java
@@ -0,0 +1,66 @@
+package org.plazmamc.plazma.commands;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import io.papermc.paper.adventure.PaperAdventure;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextComponent;
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.commands.Commands;
+import net.minecraft.commands.arguments.EntityArgument;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.player.Player;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+import org.jetbrains.annotations.Contract;
+import org.plazmamc.plazma.configurations.GlobalConfiguration;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import static net.kyori.adventure.text.minimessage.MiniMessage.miniMessage;
+
+@DefaultQualifier(NonNull.class)
+public class HealCommand {
+
+ public static void register(final CommandDispatcher<CommandSourceStack> dispatcher) {
+ dispatcher.register(Commands.literal("heal")
+ .requires(source -> source.hasPermission(2, "bukkit.command.heal"))
+ .executes(ctx -> execute(ctx.getSource(), Collections.singleton(ctx.getSource().getEntityOrException())))
+ .then(Commands.argument("targets", EntityArgument.entities())
+ .requires(source -> source.hasPermission(3, "bukkit.command.heal.others"))
+ .executes(ctx -> execute(ctx.getSource(), EntityArgument.getEntities(ctx, "targets")))
+ )
+ );
+ }
+
+ @Contract(pure = true)
+ private static int execute(final CommandSourceStack sender, Collection<? extends Entity> targets) throws CommandSyntaxException {
+ final ArrayList<Component> success = new ArrayList<>();
+
+ for (Entity target : targets) {
+ if (!(target instanceof LivingEntity entity)) continue;
+ if (entity.isDeadOrDying()) continue;
+
+ entity.heal(entity.getMaxHealth());
+ success.add(PaperAdventure.asAdventure(entity.getDisplayName()));
+
+ if (!(entity instanceof Player player)) continue;
+ player.getFoodData().setFoodLevel(20);
+ player.getFoodData().setSaturation(5.0F);
+ }
+
+ if (success.isEmpty()) {
+ throw new SimpleCommandExceptionType(PaperAdventure.asVanilla(miniMessage().deserialize(GlobalConfiguration.get().messages.heal.noTargets))).create();
+ }
+
+ final Component successJoined = success.stream().reduce((a, b) -> a.append(Component.text(", ").append(b))).orElseThrow();
+
+ sender.sendSuccess(miniMessage().deserialize(GlobalConfiguration.get().messages.heal.healed, Placeholder.component("targets", successJoined)));
+ return success.size();
+ }
+
+}
diff --git a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java
index 898f9e6ec6f306a15639ee0d03bcfe7bf55e2c6c..02a164ff2c855864e246dcaaf8186274421edea7 100644
--- a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java
+++ b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java
@@ -31,6 +31,13 @@ public class GlobalConfiguration extends ConfigurationPart {
public Messages messages;
public class Messages extends ConfigurationPart {
+ public Heal heal;
+ public class Heal extends ConfigurationPart {
+
+ public String healed = "Healed %s";
+ public String noTargets = "No targets matched selector";
+
+ }
}
diff --git a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
index 180c0a532bbac10a8280b63eb7aa783a1bfbb237..75ddd1a811d0a07c6fe5431a527b3a74e52ad53a 100644
--- a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
+++ b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
@@ -78,7 +78,8 @@ public class MinecraftCommandPermissionsTest {
"minecraft.command.gamemode.survival",
"minecraft.command.gamemode.survival.other",
// Purpur end
- "minecraft.command.selector"
+ "minecraft.command.selector",
+ "minecraft.command.heal" // Plazma
);
private static Set<String> collectMinecraftCommandPerms() {