From 70677f1956d29d2da6cc4754c674a983d7279891 Mon Sep 17 00:00:00 2001
From: daoge_cmd <3523206925@qq.com>
Date: Wed, 16 Oct 2024 17:07:11 +0800
Subject: [PATCH] feat: add /kill command
---
.../attribute/EntityAttributeComponent.java | 4 ++
.../server/command/defaults/ClearCommand.java | 21 ++++---
.../server/command/defaults/KillCommand.java | 61 +++++++++++++++++++
.../component/EntityBaseComponentImpl.java | 1 +
.../player/EntityPlayerBaseComponentImpl.java | 5 --
.../server/registry/AllayCommandRegistry.java | 1 +
6 files changed, 81 insertions(+), 12 deletions(-)
create mode 100644 server/src/main/java/org/allaymc/server/command/defaults/KillCommand.java
diff --git a/api/src/main/java/org/allaymc/api/entity/component/attribute/EntityAttributeComponent.java b/api/src/main/java/org/allaymc/api/entity/component/attribute/EntityAttributeComponent.java
index a7612140a..6f170c021 100644
--- a/api/src/main/java/org/allaymc/api/entity/component/attribute/EntityAttributeComponent.java
+++ b/api/src/main/java/org/allaymc/api/entity/component/attribute/EntityAttributeComponent.java
@@ -1,5 +1,6 @@
package org.allaymc.api.entity.component.attribute;
+import org.allaymc.api.entity.component.EntityBaseComponent;
import org.allaymc.api.entity.component.EntityComponent;
import org.cloudburstmc.nbt.NbtMap;
@@ -134,6 +135,9 @@ default void resetHealth() {
/**
* Kill the entity.
+ *
+ * Compared to {@link EntityBaseComponent#despawn()} method, this method will set the health
+ * of this entity to zero, rather than remove the entity directly.
*/
default void kill() {
setHealth(0);
diff --git a/server/src/main/java/org/allaymc/server/command/defaults/ClearCommand.java b/server/src/main/java/org/allaymc/server/command/defaults/ClearCommand.java
index e4058c83a..8fd11125f 100644
--- a/server/src/main/java/org/allaymc/server/command/defaults/ClearCommand.java
+++ b/server/src/main/java/org/allaymc/server/command/defaults/ClearCommand.java
@@ -10,7 +10,6 @@
import org.allaymc.api.item.type.ItemType;
import org.allaymc.api.item.type.ItemTypes;
-import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
@@ -36,8 +35,13 @@ public void prepareCommandTree(CommandTree tree) {
.intNum("maxCount", -1)
.optional()
.exec((context, sender) -> {
- var targets = new ArrayList();
- targets.addAll(context.getResult(0) != null ? context.getResult(0) : List.of(sender));
+ List targets = context.getResult(0);
+ if (targets != null && targets.isEmpty()) {
+ context.addNoTargetMatchError();
+ return context.fail();
+ } else if (targets == null) {
+ targets = List.of(sender);
+ }
ItemType> itemType = context.getResult(1);
int data = context.getResult(2);
@@ -46,6 +50,8 @@ public void prepareCommandTree(CommandTree tree) {
maxCount = Integer.MAX_VALUE;
}
+ boolean success = true;
+ int status = 0;
for (var target : targets) {
var containers = Stream.of(FullContainerType.PLAYER_INVENTORY, FullContainerType.OFFHAND, FullContainerType.ARMOR).map(target::getContainer).toList();
if (maxCount == 0) {
@@ -58,7 +64,7 @@ public void prepareCommandTree(CommandTree tree) {
.sum())
.sum();
context.addOutput(TrKeys.M_COMMANDS_CLEAR_TESTING, target.getOriginName(), count);
- return context.success(count);
+ status = count;
} else {
int c = maxCount;
for (var container : containers) {
@@ -81,13 +87,14 @@ public void prepareCommandTree(CommandTree tree) {
if (maxCount != c) {
context.addOutput(TrKeys.M_COMMANDS_CLEAR_SUCCESS, target.getOriginName(), maxCount - c);
} else {
- context.addOutput(TrKeys.M_COMMANDS_CLEAR_FAILURE_NO_ITEMS, target.getOriginName());
+ context.addError("%" + TrKeys.M_COMMANDS_CLEAR_FAILURE_NO_ITEMS, target.getOriginName());
+ success = false;
}
}
}
- return context.success();
+ return success ? context.success(status) : context.fail();
}, SenderType.PLAYER);
}
-}
+}
\ No newline at end of file
diff --git a/server/src/main/java/org/allaymc/server/command/defaults/KillCommand.java b/server/src/main/java/org/allaymc/server/command/defaults/KillCommand.java
new file mode 100644
index 000000000..a18de4a91
--- /dev/null
+++ b/server/src/main/java/org/allaymc/server/command/defaults/KillCommand.java
@@ -0,0 +1,61 @@
+package org.allaymc.server.command.defaults;
+
+import org.allaymc.api.command.SenderType;
+import org.allaymc.api.command.SimpleCommand;
+import org.allaymc.api.command.tree.CommandTree;
+import org.allaymc.api.entity.Entity;
+import org.allaymc.api.entity.component.attribute.EntityAttributeComponent;
+import org.allaymc.api.entity.interfaces.EntityPlayer;
+import org.allaymc.api.i18n.TrKeys;
+import org.cloudburstmc.protocol.bedrock.data.GameType;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author daoge_cmd
+ */
+public class KillCommand extends SimpleCommand {
+
+ public KillCommand() {
+ super("kill", TrKeys.M_COMMANDS_KILL_DESCRIPTION);
+ }
+
+ @Override
+ public void prepareCommandTree(CommandTree tree) {
+ tree.getRoot()
+ // Set default value to null to
+ // mark that the sender want to suicide
+ .target("targets", null)
+ .optional()
+ .exec((context, sender) -> {
+ List targets = context.getResult(0);
+ if (targets == null) {
+ targets = List.of(sender);
+ }
+
+ if (targets.stream().allMatch(target -> target instanceof EntityPlayer player && player.getGameType() == GameType.CREATIVE)) {
+ context.addError("%" + TrKeys.M_COMMANDS_KILL_ATTEMPTKILLPLAYERCREATIVE);
+ return context.fail();
+ }
+
+ Map killedEntities = new HashMap<>();
+ for (var target : targets) {
+ if (target instanceof EntityPlayer player && (player.getGameType() == GameType.CREATIVE || player.getGameType() == GameType.SPECTATOR)) {
+ continue;
+ }
+ if (target instanceof EntityAttributeComponent damageComponent) {
+ damageComponent.kill();
+ } else {
+ target.despawn();
+ }
+ killedEntities.compute(target.getCommandSenderName(), (k ,v) -> v != null ? ++v : 1);
+ }
+ context.addOutput(TrKeys.M_COMMANDS_KILL_SUCCESSFUL, killedEntities.entrySet().stream().map(entry -> entry.getKey() + " * " + entry.getValue()).collect(Collectors.joining(", ")));
+ return context.success();
+ }, SenderType.ENTITY);
+ }
+}
diff --git a/server/src/main/java/org/allaymc/server/entity/component/EntityBaseComponentImpl.java b/server/src/main/java/org/allaymc/server/entity/component/EntityBaseComponentImpl.java
index 2f3dd1014..d83c4e056 100644
--- a/server/src/main/java/org/allaymc/server/entity/component/EntityBaseComponentImpl.java
+++ b/server/src/main/java/org/allaymc/server/entity/component/EntityBaseComponentImpl.java
@@ -203,6 +203,7 @@ protected void tickEffects() {
}
protected void checkDead() {
+ // TODO: move these code to EntityAttributeComponentImpl
if (attributeComponent == null || !attributeComponent.supportHealth()) return;
if (attributeComponent.getHealth() == 0 && !dead) {
onDie();
diff --git a/server/src/main/java/org/allaymc/server/entity/component/player/EntityPlayerBaseComponentImpl.java b/server/src/main/java/org/allaymc/server/entity/component/player/EntityPlayerBaseComponentImpl.java
index af8b728d1..097a293a2 100644
--- a/server/src/main/java/org/allaymc/server/entity/component/player/EntityPlayerBaseComponentImpl.java
+++ b/server/src/main/java/org/allaymc/server/entity/component/player/EntityPlayerBaseComponentImpl.java
@@ -640,11 +640,6 @@ public void sendTr(String key, boolean forceTranslatedByClient, String... args)
} else sendText(I18n.get().tr(thisPlayer.getLangCode(), key, args));
}
- @Override
- public String getCommandSenderName() {
- return thisPlayer.getDisplayName();
- }
-
@Override
public void applyEntityEvent(EntityEventType event, int data) {
var packet = new EntityEventPacket();
diff --git a/server/src/main/java/org/allaymc/server/registry/AllayCommandRegistry.java b/server/src/main/java/org/allaymc/server/registry/AllayCommandRegistry.java
index 90edc7164..32203f374 100644
--- a/server/src/main/java/org/allaymc/server/registry/AllayCommandRegistry.java
+++ b/server/src/main/java/org/allaymc/server/registry/AllayCommandRegistry.java
@@ -67,6 +67,7 @@ private void registerDefaultCommands() {
register(new SetBlockCommand());
register(new WeatherCommand());
register(new ClearCommand());
+ register(new KillCommand());
}
@Override