9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-19 14:59:32 +00:00

Refactor fakeplayer config and fix some subcommand

This commit is contained in:
violetc
2025-03-15 03:49:29 +08:00
parent c3651150b0
commit 9562d0bbc6
17 changed files with 173 additions and 147 deletions

View File

@@ -98,7 +98,7 @@ public class ServerBot extends ServerPlayer {
ImmutableMap.Builder<Configs<?>, AbstractBotConfig<?>> configBuilder = ImmutableMap.builder();
for (Configs<?> config : Configs.getConfigs()) {
configBuilder.put(config, config.config.create(this));
configBuilder.put(config, config.createConfig(this));
}
this.configs = configBuilder.build();

View File

@@ -7,19 +7,17 @@ import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import java.util.List;
import java.util.function.Supplier;
public abstract class AbstractBotConfig<E> {
private final String name;
private final CommandArgument argument;
private final Supplier<AbstractBotConfig<E>> creator;
protected ServerBot bot;
public AbstractBotConfig(String name, CommandArgument argument, Supplier<AbstractBotConfig<E>> creator) {
public AbstractBotConfig(String name, CommandArgument argument) {
this.name = name;
this.argument = argument;
this.creator = creator;
}
public AbstractBotConfig<E> setBot(ServerBot bot) {
@@ -29,7 +27,19 @@ public abstract class AbstractBotConfig<E> {
public abstract E getValue();
public abstract void setValue(@NotNull CommandArgumentResult result) throws IllegalArgumentException;
public abstract void setValue(E value) throws IllegalArgumentException;
@SuppressWarnings("unchecked")
public void setFromCommand(@NotNull CommandArgumentResult result) throws IllegalArgumentException {
if (argument == CommandArgument.EMPTY) {
throw new IllegalArgumentException("No argument for " + this.getName());
}
try {
this.setValue((E) result.read(argument.getArgumentTypes().getFirst().getType()));
} catch (ClassCastException e) {
throw new IllegalArgumentException("Invalid argument type for " + this.getName() + ": " + e.getMessage());
}
}
public List<String> getMessage() {
return List.of(this.bot.getScoreboardName() + "'s " + this.getName() + ": " + this.getValue());
@@ -47,11 +57,6 @@ public abstract class AbstractBotConfig<E> {
return argument;
}
@NotNull
public AbstractBotConfig<E> create(ServerBot bot) {
return this.creator.get().setBot(bot);
}
@NotNull
public CompoundTag save(@NotNull CompoundTag nbt) {
nbt.putString("configName", this.name);

View File

@@ -3,32 +3,38 @@ package org.leavesmc.leaves.bot.agent;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.bot.agent.configs.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
@SuppressWarnings("unused")
public class Configs<E> {
private static final Map<String, Configs<?>> configs = new HashMap<>();
public static final Configs<Boolean> SKIP_SLEEP = register(new SkipSleepConfig());
public static final Configs<Boolean> ALWAYS_SEND_DATA = register(new AlwaysSendDataConfig());
public static final Configs<Boolean> SPAWN_PHANTOM = register(new SpawnPhantomConfig());
public static final Configs<Integer> SIMULATION_DISTANCE = register(new SimulationDistanceConfig());
public static final Configs<Boolean> SKIP_SLEEP = register(SkipSleepConfig.class, SkipSleepConfig::new);
public static final Configs<Boolean> ALWAYS_SEND_DATA = register(AlwaysSendDataConfig.class, AlwaysSendDataConfig::new);
public static final Configs<Boolean> SPAWN_PHANTOM = register(SpawnPhantomConfig.class, SpawnPhantomConfig::new);
public static final Configs<Integer> SIMULATION_DISTANCE = register(SimulationDistanceConfig.class, SimulationDistanceConfig::new);
public final AbstractBotConfig<E> config;
private final Class<? extends AbstractBotConfig<E>> configClass;
private final Supplier<? extends AbstractBotConfig<E>> configCreator;
private Configs(AbstractBotConfig<E> config) {
this.config = config;
private Configs(Class<? extends AbstractBotConfig<E>> configClass, Supplier<? extends AbstractBotConfig<E>> configCreator) {
this.configClass = configClass;
this.configCreator = configCreator;
}
@NotNull
@Contract(pure = true)
public static Collection<Configs<?>> getConfigs() {
return configs.values();
public Class<? extends AbstractBotConfig<E>> getConfigClass() {
return configClass;
}
public AbstractBotConfig<E> createConfig(ServerBot bot) {
return configCreator.get().setBot(bot);
}
@Nullable
@@ -37,9 +43,21 @@ public class Configs<E> {
}
@NotNull
private static <T> Configs<T> register(AbstractBotConfig<T> botConfig) {
Configs<T> config = new Configs<>(botConfig);
configs.put(botConfig.getName(), config);
@Contract(pure = true)
public static Collection<Configs<?>> getConfigs() {
return configs.values();
}
@NotNull
@Contract(pure = true)
public static Collection<String> getConfigNames() {
return configs.keySet();
}
@NotNull
private static <E> Configs<E> register(Class<? extends AbstractBotConfig<E>> configClass, Supplier<? extends AbstractBotConfig<E>> configCreator) {
Configs<E> config = new Configs<>(configClass, configCreator);
configs.put(config.createConfig(null).getName(), config);
return config;
}
}

View File

@@ -6,17 +6,18 @@ import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.bot.agent.AbstractBotConfig;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import java.util.List;
public class AlwaysSendDataConfig extends AbstractBotConfig<Boolean> {
public static final String NAME = "always_send_data";
private boolean value;
public AlwaysSendDataConfig() {
super("always_send_data", CommandArgument.of(CommandArgumentType.BOOLEAN).setTabComplete(0, List.of("true", "false")), AlwaysSendDataConfig::new);
super(NAME, CommandArgument.of(CommandArgumentType.BOOLEAN).setTabComplete(0, List.of("true", "false")));
this.value = LeavesConfig.modify.fakeplayer.canSendDataAlways;
}
@@ -26,20 +27,20 @@ public class AlwaysSendDataConfig extends AbstractBotConfig<Boolean> {
}
@Override
public void setValue(@NotNull CommandArgumentResult result) throws IllegalArgumentException {
this.value = result.readBoolean(this.value);
public void setValue(Boolean value) {
this.value = value;
}
@Override
@NotNull
public CompoundTag save(@NotNull CompoundTag nbt) {
super.save(nbt);
nbt.putBoolean("always_send_data", this.getValue());
nbt.putBoolean(NAME, this.getValue());
return nbt;
}
@Override
public void load(@NotNull CompoundTag nbt) {
this.value = nbt.getBoolean("always_send_data");
this.setValue(nbt.getBoolean(NAME));
}
}

View File

@@ -4,16 +4,16 @@ import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.agent.AbstractBotConfig;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import java.util.ArrayList;
import java.util.List;
public class SimulationDistanceConfig extends AbstractBotConfig<Integer> {
public static final String NAME = "simulation_distance";
public SimulationDistanceConfig() {
super("simulation_distance", CommandArgument.of(CommandArgumentType.INTEGER).setTabComplete(0, List.of("2", "10", "<INT 2 - 32>")), SimulationDistanceConfig::new);
super(NAME, CommandArgument.of(CommandArgumentType.INTEGER).setTabComplete(0, List.of("2", "10", "<INT 2 - 32>")));
}
@Override
@@ -22,26 +22,23 @@ public class SimulationDistanceConfig extends AbstractBotConfig<Integer> {
}
@Override
public void setValue(@NotNull CommandArgumentResult result) throws IllegalArgumentException {
int realValue = result.readInt(this.bot.getBukkitEntity().getSimulationDistance());
if (realValue < 2 || realValue > 32) {
throw new IllegalArgumentException("simulation_distance must be a number between 2 and 32, got: " + result);
public void setValue(Integer value) {
if (value < 2 || value > 32) {
throw new IllegalArgumentException("simulation_distance must be a number between 2 and 32, got: " + value);
}
this.bot.getBukkitEntity().setSimulationDistance(realValue);
this.bot.getBukkitEntity().setSimulationDistance(value);
}
@Override
@NotNull
public CompoundTag save(@NotNull CompoundTag nbt) {
super.save(nbt);
nbt.putInt("simulation_distance", this.getValue());
nbt.putInt(NAME, this.getValue());
return nbt;
}
@Override
public void load(@NotNull CompoundTag nbt) {
this.setValue(new CommandArgumentResult(new ArrayList<>() {{
add(nbt.getInt("simulation_distance"));
}}));
this.setValue(nbt.getInt(NAME));
}
}

View File

@@ -4,16 +4,16 @@ import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.agent.AbstractBotConfig;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import java.util.ArrayList;
import java.util.List;
public class SkipSleepConfig extends AbstractBotConfig<Boolean> {
public static final String NAME = "skip_sleep";
public SkipSleepConfig() {
super("skip_sleep", CommandArgument.of(CommandArgumentType.BOOLEAN).setTabComplete(0, List.of("true", "false")), SkipSleepConfig::new);
super(NAME, CommandArgument.of(CommandArgumentType.BOOLEAN).setTabComplete(0, List.of("true", "false")));
}
@Override
@@ -22,21 +22,19 @@ public class SkipSleepConfig extends AbstractBotConfig<Boolean> {
}
@Override
public void setValue(@NotNull CommandArgumentResult result) throws IllegalArgumentException {
bot.fauxSleeping = result.readBoolean(bot.fauxSleeping);
public void setValue(Boolean value) throws IllegalArgumentException {
bot.fauxSleeping = value;
}
@Override
public @NotNull CompoundTag save(@NotNull CompoundTag nbt) {
super.save(nbt);
nbt.putBoolean("skip_sleep", this.getValue());
nbt.putBoolean(NAME, this.getValue());
return nbt;
}
@Override
public void load(@NotNull CompoundTag nbt) {
this.setValue(new CommandArgumentResult(new ArrayList<>() {{
add(nbt.getBoolean("skip_sleep"));
}}));
this.setValue(nbt.getBoolean(NAME));
}
}

View File

@@ -5,17 +5,18 @@ import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.bot.agent.AbstractBotConfig;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import java.util.List;
public class SpawnPhantomConfig extends AbstractBotConfig<Boolean> {
public static final String NAME = "spawn_phantom";
private boolean value;
public SpawnPhantomConfig() {
super("spawn_phantom", CommandArgument.of(CommandArgumentType.BOOLEAN).setTabComplete(0, List.of("true", "false")), SpawnPhantomConfig::new);
super(NAME, CommandArgument.of(CommandArgumentType.BOOLEAN).setTabComplete(0, List.of("true", "false")));
this.value = LeavesConfig.modify.fakeplayer.canSpawnPhantom;
}
@@ -25,8 +26,8 @@ public class SpawnPhantomConfig extends AbstractBotConfig<Boolean> {
}
@Override
public void setValue(@NotNull CommandArgumentResult result) throws IllegalArgumentException {
this.value = result.readBoolean(this.value);
public void setValue(Boolean value) throws IllegalArgumentException {
this.value = value;
}
@Override
@@ -40,12 +41,12 @@ public class SpawnPhantomConfig extends AbstractBotConfig<Boolean> {
@Override
public @NotNull CompoundTag save(@NotNull CompoundTag nbt) {
super.save(nbt);
nbt.putBoolean("spawn_phantom", this.getValue());
nbt.putBoolean(NAME, this.getValue());
return nbt;
}
@Override
public void load(@NotNull CompoundTag nbt) {
this.value = nbt.getBoolean("spawn_phantom");
this.setValue(nbt.getBoolean(NAME));
}
}

View File

@@ -22,6 +22,7 @@ import java.util.Set;
import static net.kyori.adventure.text.Component.text;
public class BotActionCommand implements LeavesSubcommand {
@Override
public boolean execute(CommandSender sender, String subCommand, String[] args) {
if (!LeavesConfig.modify.fakeplayer.canUseAction) {
@@ -53,7 +54,7 @@ public class BotActionCommand implements LeavesSubcommand {
return false;
}
String index = args[4];
String index = args[2];
if (index.equals("all")) {
Set<AbstractBotAction<?>> forRemoval = new HashSet<>();
for (int i = 0; i < bot.getBotActions().size(); i++) {
@@ -145,6 +146,10 @@ public class BotActionCommand implements LeavesSubcommand {
if (args.length <= 1) {
list.addAll(botList.bots.stream().map(e -> e.getName().getString()).toList());
} else {
ServerBot bot = botList.getBotByName(args[0]);
if (bot == null) {
return Collections.singletonList("<" + args[0] + " not found>");
}
if (args.length == 2) {
@@ -154,12 +159,6 @@ public class BotActionCommand implements LeavesSubcommand {
}
if (args.length >= 3) {
ServerBot bot = botList.getBotByName(args[0]);
if (bot == null) {
return Collections.singletonList("<" + args[0] + " not found>");
}
if (args[1].equals("stop")) {
list.add("all");
for (int i = 0; i < bot.getBotActions().size(); i++) {
@@ -172,6 +171,7 @@ public class BotActionCommand implements LeavesSubcommand {
}
}
}
}
return list;
}

View File

@@ -21,7 +21,6 @@ import java.util.Objects;
import static net.kyori.adventure.text.Component.text;
public class BotConfigCommand implements LeavesSubcommand {
private static final List<String> acceptConfig = Configs.getConfigs().stream().map(config -> config.config.getName()).toList();
@Override
public boolean execute(CommandSender sender, String subCommand, String[] args) {
@@ -29,28 +28,28 @@ public class BotConfigCommand implements LeavesSubcommand {
return false;
}
if (args.length < 3) {
if (args.length < 2) {
sender.sendMessage(text("Use /bot config <name> <config> to modify fakeplayer's config", NamedTextColor.RED));
return false;
}
ServerBot bot = BotList.INSTANCE.getBotByName(args[1]);
ServerBot bot = BotList.INSTANCE.getBotByName(args[0]);
if (bot == null) {
sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED));
return false;
}
if (!acceptConfig.contains(args[2])) {
if (!Configs.getConfigNames().contains(args[1])) {
sender.sendMessage(text("This config is not accept", NamedTextColor.RED));
return false;
}
AbstractBotConfig<?> config = Objects.requireNonNull(Configs.getConfig(args[2])).config;
if (args.length < 4) {
AbstractBotConfig<?> config = bot.getConfig(Objects.requireNonNull(Configs.getConfig(args[1])));
if (args.length < 3) {
config.getMessage().forEach(sender::sendMessage);
} else {
String[] realArgs = new String[args.length - 3];
System.arraycopy(args, 3, realArgs, 0, realArgs.length);
String[] realArgs = new String[args.length - 2];
System.arraycopy(args, 2, realArgs, 0, realArgs.length);
BotConfigModifyEvent event = new BotConfigModifyEvent(bot.getBukkitEntity(), config.getName(), realArgs, sender);
Bukkit.getPluginManager().callEvent(event);
@@ -61,7 +60,7 @@ public class BotConfigCommand implements LeavesSubcommand {
CommandArgumentResult result = config.getArgument().parse(0, realArgs);
try {
config.setValue(result);
config.setFromCommand(result);
config.getChangeMessage().forEach(sender::sendMessage);
} catch (IllegalArgumentException e) {
sender.sendMessage(text(e.getMessage(), NamedTextColor.RED));
@@ -81,16 +80,23 @@ public class BotConfigCommand implements LeavesSubcommand {
if (args.length <= 1) {
list.addAll(botList.bots.stream().map(e -> e.getName().getString()).toList());
}
} else {
ServerBot bot = botList.getBotByName(args[0]);
if (bot == null) {
return Collections.singletonList("<" + args[0] + " not found>");
} else {
if (args.length == 2) {
list.addAll(acceptConfig);
list.addAll(Configs.getConfigNames());
}
if (args.length >= 3) {
Configs<?> config = Configs.getConfig(args[1]);
if (config != null) {
list.addAll(config.config.getArgument().tabComplete(args.length - 3));
list.addAll(bot.getConfig(config).getArgument().tabComplete(args.length - 3));
} else {
return Collections.singletonList("<" + args[1] + " not found>");
}
}
}
}

View File

@@ -21,6 +21,7 @@ import java.util.List;
import static net.kyori.adventure.text.Component.text;
public class BotCreateCommand implements LeavesSubcommand {
@Override
public boolean execute(CommandSender sender, String subCommand, String[] args) {
if (args.length < 1) {

View File

@@ -21,6 +21,7 @@ import java.util.Map;
import static net.kyori.adventure.text.Component.text;
public class BotListCommand implements LeavesSubcommand {
@Override
public boolean execute(CommandSender sender, String subCommand, String[] args) {
BotList botList = BotList.INSTANCE;

View File

@@ -14,18 +14,19 @@ import java.util.List;
import static net.kyori.adventure.text.Component.text;
public class BotLoadCommand implements LeavesSubcommand {
@Override
public boolean execute(CommandSender sender, String subCommand, String[] args) {
if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) {
return false;
}
if (args.length < 2) {
if (args.length < 1) {
sender.sendMessage(text("Use /bot load <name> to save a fakeplayer", NamedTextColor.RED));
return false;
}
String realName = args[1];
String realName = args[0];
BotList botList = BotList.INSTANCE;
if (!botList.getSavedBotList().contains(realName)) {
sender.sendMessage(text("This fakeplayer is not saved", NamedTextColor.RED));

View File

@@ -17,6 +17,7 @@ import java.util.List;
import static net.kyori.adventure.text.Component.text;
public class BotRemoveCommand implements LeavesSubcommand {
private final Component errorMessage = text("Usage: /bot remove <name> [hour] [minute] [second]", NamedTextColor.RED);
@Override

View File

@@ -16,19 +16,20 @@ import java.util.List;
import static net.kyori.adventure.text.Component.text;
public class BotSaveCommand implements LeavesSubcommand {
@Override
public boolean execute(CommandSender sender, String subCommand, String[] args) {
if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) {
return false;
}
if (args.length < 2) {
if (args.length < 1) {
sender.sendMessage(text("Use /bot save <name> to save a fakeplayer", NamedTextColor.RED));
return false;
}
BotList botList = BotList.INSTANCE;
ServerBot bot = botList.getBotByName(args[1]);
ServerBot bot = botList.getBotByName(args[0]);
if (bot == null) {
sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED));

View File

@@ -44,11 +44,15 @@ public class CommandArgument {
return this;
}
public List<CommandArgumentType<?>> getArgumentTypes() {
return argumentTypes;
}
public CommandArgumentResult parse(int index, String @NotNull [] args) {
Object[] result = new Object[argumentTypes.size()];
Arrays.fill(result, null);
for (int i = index, j = 0; i < args.length && j < result.length; i++, j++) {
result[j] = argumentTypes.get(j).pasre(args[i]);
result[j] = argumentTypes.get(j).parse(args[i]);
}
return new CommandArgumentResult(new ArrayList<>(Arrays.asList(result)));
}

View File

@@ -54,12 +54,16 @@ public class CommandArgumentResult {
return new Vector(pos[0], pos[1], pos[2]);
}
public <T> T read(Class<T> tClass, T def) {
return Objects.requireNonNullElse(read(tClass), def);
}
public <T> T read(Class<T> tClass) {
if (result.isEmpty()) {
return null;
}
Object obj = result.remove(0);
Object obj = result.removeFirst();
if (tClass.isInstance(obj)) {
return tClass.cast(obj);
} else {

View File

@@ -1,55 +1,42 @@
package org.leavesmc.leaves.command;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.function.Function;
public abstract class CommandArgumentType<E> {
public static final CommandArgumentType<Integer> INTEGER = new CommandArgumentType<>() {
public static final CommandArgumentType<Integer> INTEGER = CommandArgumentType.of(Integer.class, Integer::parseInt);
public static final CommandArgumentType<Double> DOUBLE = CommandArgumentType.of(Double.class, Double::parseDouble);
public static final CommandArgumentType<Float> FLOAT = CommandArgumentType.of(Float.class, Float::parseFloat);
public static final CommandArgumentType<String> STRING = CommandArgumentType.of(String.class, (arg) -> arg);
public static final CommandArgumentType<Boolean> BOOLEAN = CommandArgumentType.of(Boolean.class, Boolean::parseBoolean);
private final Class<E> type;
private CommandArgumentType(Class<E> type) {
this.type = type;
}
@NotNull
@Contract(value = "_, _ -> new", pure = true)
public static <E> CommandArgumentType<E> of(Class<E> type, Function<String, E> parse) {
return new CommandArgumentType<>(type) {
@Override
public Integer pasre(@NotNull String arg) {
public E parse(@NotNull String arg) {
try {
return Integer.parseInt(arg);
} catch (NumberFormatException e) {
return parse.apply(arg);
} catch (Exception ignore) {
return null;
}
}
};
}
public static final CommandArgumentType<Double> DOUBLE = new CommandArgumentType<>() {
@Override
public Double pasre(@NotNull String arg) {
try {
return Double.parseDouble(arg);
} catch (NumberFormatException e) {
return null;
public Class<E> getType() {
return type;
}
}
};
public static final CommandArgumentType<Float> FLOAT = new CommandArgumentType<>() {
@Override
public Float pasre(@NotNull String arg) {
try {
return Float.parseFloat(arg);
} catch (NumberFormatException e) {
return null;
}
}
};
public static final CommandArgumentType<String> STRING = new CommandArgumentType<>() {
@Override
public String pasre(@NotNull String arg) {
return arg;
}
};
public static final CommandArgumentType<Boolean> BOOLEAN = new CommandArgumentType<>() {
@Override
public Boolean pasre(@NotNull String arg) {
return Boolean.parseBoolean(arg);
}
};
public abstract E pasre(@NotNull String arg);
public abstract E parse(@NotNull String arg);
}