diff --git a/api/src/main/java/com/alttd/essentia/api/model/MobData.java b/api/src/main/java/com/alttd/essentia/api/model/MobData.java new file mode 100644 index 0000000..153944b --- /dev/null +++ b/api/src/main/java/com/alttd/essentia/api/model/MobData.java @@ -0,0 +1,23 @@ +package com.alttd.essentia.api.model; + +public enum MobData { + + ITEMS, + ARROWS, + BOATS, + MINECARTS, + XP, + PAINTINGS, + ITEMFRAMES, + ENDERCRYSTALS, + FIREWORKS, + HOSTILE, + MONSTERS, + PASSIVE, + ANIMALS, + AMBIENT, + MOBS, + ENTITIES, + TAMED + +} diff --git a/plugin/src/main/java/com/alttd/essentia/commands/admin/KillallCommand.java b/plugin/src/main/java/com/alttd/essentia/commands/admin/KillallCommand.java new file mode 100644 index 0000000..2807a48 --- /dev/null +++ b/plugin/src/main/java/com/alttd/essentia/commands/admin/KillallCommand.java @@ -0,0 +1,246 @@ +package com.alttd.essentia.commands.admin; + +import com.alttd.essentia.api.model.MobData; +import com.alttd.essentia.commands.EssentiaCommand; +import com.alttd.essentia.commands.argumement.EntityTypeArgumentType; +import com.alttd.essentia.commands.argumement.MobDataArgumentType; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.*; +import org.jetbrains.annotations.NotNull; + +public class KillallCommand implements EssentiaCommand { + + @Override + public String commandName() { + return "killall"; + } + + @Override + public @NotNull LiteralCommandNode command() { + final LiteralArgumentBuilder builder = + Commands.literal(commandName()) + .requires( + commandSourceStack -> commandSourceStack.getSender().hasPermission(adminCommandPermission()) && + commandSourceStack.getSender() instanceof Player + ) + .then(Commands.argument("mobdata", new MobDataArgumentType()) + .executes((source) -> { + if (!(source.getSource().getSender() instanceof Player player)) + return 1; + + MobData mobData = source.getArgument("mobdata", MobData.class); + execute(source.getSource().getSender(), player, mobData, 50, false); + return 1; + }) + .then(Commands.argument("radius", IntegerArgumentType.integer(0, 250)) + .executes((source) -> { + if (!(source.getSource().getSender() instanceof Player player)) + return 1; + + MobData mobData = source.getArgument("mobdata", MobData.class); + int radius = source.getArgument("radius", Integer.class); + execute(source.getSource().getSender(), player, mobData, radius, false); + return 1; + }) + .then(Commands.literal("named") + .executes((source) -> { + if (!(source.getSource().getSender() instanceof Player player)) + return 1; + + MobData mobData = source.getArgument("mobdata", MobData.class); + int radius = source.getArgument("range", Integer.class); + execute(source.getSource().getSender(), player, mobData, radius, true); + return 1; + }) + ) + + ) + ) +// .then(Commands.argument("entitytype", new EntityTypeArgumentType()) +// .executes((source) -> { +// if (!(source.getSource().getSender() instanceof Player player)) +// return 1; +// +// EntityType entityType = source.getArgument("entitytype", EntityType.class); +// execute(source.getSource().getSender(), player, entityType, 50, false); +// return 1; +// }) +// .then(Commands.argument("radius", IntegerArgumentType.integer(0, 250)) +// .executes((source) -> { +// if (!(source.getSource().getSender() instanceof Player player)) +// return 1; +// +// EntityType entityType = source.getArgument("entitytype", EntityType.class); +// int radius = source.getArgument("radius", Integer.class); +// execute(source.getSource().getSender(), player, entityType, radius, false); +// return 1; +// }) +// .then(Commands.literal("named") +// .executes((source) -> { +// if (!(source.getSource().getSender() instanceof Player player)) +// return 1; +// +// EntityType entityType = source.getArgument("entitytype", EntityType.class); +// int radius = source.getArgument("range", Integer.class); +// execute(source.getSource().getSender(), player, entityType, radius, true); +// return 1; +// }) +// ) +// +// ) +// ) + ; + return builder.build(); + } + + public void execute(CommandSender sender, Player target, MobData mobData, int radius, boolean named) { // TODO - Messages from config, placeholders + TagResolver placeholders = TagResolver.resolver( + Placeholder.component("requester", sender.name()), + Placeholder.component("target", target.displayName()) + ); + + int removed = 0; + + for (Entity entity : target.getNearbyEntities(radius, radius, radius)) { + if (entity instanceof HumanEntity) + continue; + + // PERFORMANCE hit? + if (entity instanceof Tameable tameable && (tameable.isTamed() && tameable.getOwner() instanceof Player || tameable.getOwner() instanceof OfflinePlayer) && mobData != MobData.TAMED) + continue; + + // TODO - named entities + if (entity instanceof LivingEntity && entity.customName() != null) + continue; + + switch (mobData) { + case ITEMS -> { + if (entity instanceof Item) { + entity.remove(); + removed++; + } + } + case ARROWS -> { + if (entity instanceof Projectile) { + entity.remove(); + removed++; + } + } + case BOATS -> { + if (entity instanceof Boat) { + entity.remove(); + removed++; + } + } + case MINECARTS -> { + if (entity instanceof Minecart) { + entity.remove(); + removed++; + } + } + case XP -> { + if (entity instanceof ExperienceOrb) { + entity.remove(); + removed++; + } + } + case PAINTINGS -> { + if (entity instanceof Painting) { + entity.remove(); + removed++; + } + } + case ITEMFRAMES -> { + if (entity instanceof ItemFrame) { + entity.remove(); + removed++; + } + } + case ENDERCRYSTALS -> { + if (entity instanceof EnderCrystal) { + entity.remove(); + removed++; + } + } + case FIREWORKS -> { + if (entity instanceof Firework) { + entity.remove(); + removed++; + } + } + case HOSTILE, MONSTERS -> { + if (entity instanceof Monster ||entity instanceof ComplexLivingEntity || entity instanceof Flying || entity instanceof Slime) { + entity.remove(); + removed++; + } + } + case PASSIVE, ANIMALS -> { + if (entity instanceof Animals || entity instanceof Snowman || entity instanceof WaterMob || entity instanceof Ambient) { + entity.remove(); + removed++; + } + } + case AMBIENT -> { + if (entity instanceof Ambient) { + entity.remove(); + removed++; + } + } + case MOBS -> { + if (entity instanceof Monster ||entity instanceof ComplexLivingEntity || entity instanceof Flying || entity instanceof Slime || entity instanceof Animals || entity instanceof Snowman || entity instanceof WaterMob || entity instanceof Ambient) { + entity.remove(); + removed++; + } + } + case ENTITIES -> { + entity.remove(); + removed++; + } + case TAMED -> { + if (entity instanceof Tameable tameable && tameable.isTamed()) { + entity.remove(); + removed++; + } + } + } + } + + } + + public void execute(CommandSender sender, Player target, EntityType entityType, int radius, boolean named) { // TODO - Messages from config, placeholders + TagResolver placeholders = TagResolver.resolver( + Placeholder.component("requester", sender.name()), + Placeholder.component("target", target.displayName()) + ); + + int removed = 0; + + for (Entity entity : target.getNearbyEntities(radius, radius, radius)) { + if (entity instanceof HumanEntity) + continue; + + // PERFORMANCE hit? + if (entity instanceof Tameable tameable && (tameable.isTamed() && tameable.getOwner() instanceof Player || tameable.getOwner() instanceof OfflinePlayer)) + continue; + + // TODO - named entities + if (entity instanceof LivingEntity && entity.customName() != null) + continue; + + if (entity.getType() == entityType) { + entity.remove(); + removed++; + } + } + + } + +} diff --git a/plugin/src/main/java/com/alttd/essentia/commands/argumement/EntityTypeArgumentType.java b/plugin/src/main/java/com/alttd/essentia/commands/argumement/EntityTypeArgumentType.java new file mode 100644 index 0000000..4c0aeb8 --- /dev/null +++ b/plugin/src/main/java/com/alttd/essentia/commands/argumement/EntityTypeArgumentType.java @@ -0,0 +1,52 @@ +package com.alttd.essentia.commands.argumement; + +import com.alttd.essentia.commands.EssentiaArgument; +import com.mojang.brigadier.Message; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.MessageComponentSerializer; +import io.papermc.paper.command.brigadier.argument.CustomArgumentType; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.EntityType; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +// TODO -- add a wrapper for entitytype and only list those we want to list as this large list breaks tabcomplete +public class EntityTypeArgumentType implements CustomArgumentType.Converted, EssentiaArgument { + + @Override + public @NotNull EntityType convert(String nativeType) throws CommandSyntaxException { + try { + return EntityType.valueOf(nativeType.toUpperCase()); + } catch (Exception e) { + Message message = MessageComponentSerializer.message().serialize(Component.text("Invalid EntityType %s!".formatted(nativeType), NamedTextColor.RED)); + + throw new CommandSyntaxException(new SimpleCommandExceptionType(message), message); + } + } + + @Override + public @NotNull ArgumentType getNativeType() { + return StringArgumentType.word(); + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + Collection possibleValues = new ArrayList<>(); + for (EntityType entityType : EntityType.values()) { + possibleValues.add(entityType.name().toLowerCase()); + } + + return completedFuture(builder, possibleValues); + } + +} diff --git a/plugin/src/main/java/com/alttd/essentia/commands/argumement/MobDataArgumentType.java b/plugin/src/main/java/com/alttd/essentia/commands/argumement/MobDataArgumentType.java new file mode 100644 index 0000000..5f6f48c --- /dev/null +++ b/plugin/src/main/java/com/alttd/essentia/commands/argumement/MobDataArgumentType.java @@ -0,0 +1,51 @@ +package com.alttd.essentia.commands.argumement; + +import com.alttd.essentia.api.model.MobData; +import com.alttd.essentia.commands.EssentiaArgument; +import com.mojang.brigadier.Message; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.MessageComponentSerializer; +import io.papermc.paper.command.brigadier.argument.CustomArgumentType; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +public class MobDataArgumentType implements CustomArgumentType.Converted, EssentiaArgument { + + @Override + public @NotNull MobData convert(String nativeType) throws CommandSyntaxException { + try { + return MobData.valueOf(nativeType.toUpperCase()); + } catch (Exception e) { + Message message = MessageComponentSerializer.message().serialize(Component.text("Invalid mobdatatype %s!".formatted(nativeType), NamedTextColor.RED)); + + throw new CommandSyntaxException(new SimpleCommandExceptionType(message), message); + } + } + + @Override + public @NotNull ArgumentType getNativeType() { + return StringArgumentType.word(); + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + Collection possibleValues = new ArrayList<>(); + for (MobData mobData : MobData.values()) { + possibleValues.add(mobData.name().toLowerCase()); + } + + return completedFuture(builder, possibleValues); + } + +}