package emu.grasscutter.command.commands; import static emu.grasscutter.command.CommandHelpers.*; import static emu.grasscutter.utils.Language.translate; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; import emu.grasscutter.game.entity.*; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ElementType; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.world.Scene; import emu.grasscutter.server.event.entity.EntityDamageEvent; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; import java.util.regex.Pattern; import lombok.Setter; @Command( label = "entity", usage = { " [state] [maxhp] [hp(0 for infinite)] [atk] [def]", " [ai] [maxhp] [hp(0 for infinite)] [atk] [def]" }, permission = "server.entity") public final class EntityCommand implements CommandHandler { private static final Map> intCommandHandlers = Map.ofEntries( Map.entry(stateRegex, EntityParameters::setState), Map.entry(maxHPRegex, EntityParameters::setMaxHP), Map.entry(hpRegex, EntityParameters::setHp), Map.entry(defRegex, EntityParameters::setDef), Map.entry(atkRegex, EntityParameters::setAtk), Map.entry(aiRegex, EntityParameters::setAi)); @Override public void execute(Player sender, Player targetPlayer, List args) { EntityParameters param = new EntityParameters(); parseIntParameters(args, param, intCommandHandlers); // At this point, first remaining argument MUST be the id and the rest the pos if (args.size() != 1) { sendUsageMessage(sender); // Reachable if someone does `/give lv90` or similar throw new IllegalArgumentException(); } try { param.configId = Integer.parseInt(args.get(0)); } catch (NumberFormatException ignored) { CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.cfgId")); } param.scene = targetPlayer.getScene(); var entity = param.scene.getEntityByConfigId(param.configId); if (entity == null) { CommandHandler.sendMessage(sender, translate(sender, "commands.entity.not_found_error")); return; } applyFightProps(entity, param); applyGadgetParams(entity, param); applyMonsterParams(entity, param); CommandHandler.sendMessage(sender, translate(sender, "commands.status.success")); } private void applyGadgetParams(GameEntity entity, EntityParameters param) { if (!(entity instanceof EntityGadget)) { return; } if (param.state != -1) { ((EntityGadget) entity).updateState(param.state); } } private void applyMonsterParams(GameEntity entity, EntityParameters param) { if (!(entity instanceof EntityMonster)) { return; } if (param.ai != -1) { ((EntityMonster) entity).setAiId(param.ai); // TODO notify } } private void applyFightProps(GameEntity entity, EntityParameters param) { var changedFields = new ArrayList(); if (param.maxHP != -1) { setFightProperty(entity, FightProperty.FIGHT_PROP_MAX_HP, param.maxHP, changedFields); } if (param.hp != -1) { float targetHp = param.hp == 0 ? Float.MAX_VALUE : param.hp; float oldHp = entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); setFightProperty(entity, FightProperty.FIGHT_PROP_CUR_HP, targetHp, changedFields); EntityDamageEvent event = new EntityDamageEvent(entity, oldHp - targetHp, ElementType.None, null); callHPEvents(entity, event); } if (param.atk != -1) { setFightProperty(entity, FightProperty.FIGHT_PROP_ATTACK, param.atk, changedFields); setFightProperty(entity, FightProperty.FIGHT_PROP_CUR_ATTACK, param.atk, changedFields); } if (param.def != -1) { setFightProperty(entity, FightProperty.FIGHT_PROP_DEFENSE, param.def, changedFields); setFightProperty(entity, FightProperty.FIGHT_PROP_CUR_DEFENSE, param.def, changedFields); } if (!changedFields.isEmpty()) { entity .getScene() .broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, changedFields)); } } private void callHPEvents(GameEntity entity, EntityDamageEvent event) { entity.runLuaCallbacks(event); } private void setFightProperty( GameEntity entity, FightProperty property, float value, List modifiedProps) { entity.setFightProperty(property, value); modifiedProps.add(property); } private static class EntityParameters { @Setter public int configId = -1; @Setter public int state = -1; @Setter public int hp = -1; @Setter public int maxHP = -1; @Setter public int atk = -1; @Setter public int def = -1; @Setter public int ai = -1; public Scene scene = null; } }