commands work but i think ill refactor

This commit is contained in:
kento2 2026-02-21 00:43:28 +01:00
parent 5b5cb04f8b
commit 36a13443db
54 changed files with 726 additions and 812 deletions

View file

@ -1,6 +1,6 @@
package de.kentoj.scrow.bukkit;
import de.kentoj.scrow.bukkit.friends.command.LaunchCommand;
import de.kentoj.scrow.bukkit.economy.command.CoinsCommand;
import org.bukkit.plugin.java.JavaPlugin;
import reactor.core.publisher.Mono;
@ -13,7 +13,7 @@ public class CoreImplPlugin extends JavaPlugin {
ScrowAPISurface.initScrowAPI(this, false);
{
ScrowAPI.getCommandManager().register(new LaunchCommand(), this);
ScrowAPI.getCommandManager().register(new CoinsCommand().create(), this);
}
{

View file

@ -4,11 +4,11 @@ import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import de.kentoj.scrow.bukkit.command.bukkit.CommandManagerImpl;
import de.kentoj.scrow.bukkit.command.node.CommandNodeFactoryImpl;
import de.kentoj.scrow.bukkit.cmds2.CommandFactoryImpl;
import de.kentoj.scrow.bukkit.cmds2.CommandManagerImpl;
import de.kentoj.scrow.bukkit.economy.InMemoryEconomyService;
import de.kentoj.scrow.bukkit.economy.MongoEconomyService;
import de.kentoj.scrow.bukkit.services.command.node.CommandNodeRepository;
import de.kentoj.scrow.bukkit.services.command.cmds2.Commands;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.bson.UuidRepresentation;
@ -48,7 +48,7 @@ public class ScrowAPISurface {
new MongoEconomyService(ScrowAPI.getDatabase()) : new InMemoryEconomyService()
);
CommandNodeRepository.setCommandNodeFactory(new CommandNodeFactoryImpl());
Commands.setFactory(new CommandFactoryImpl());
ScrowAPI.setCommandManager(new CommandManagerImpl());
}

View file

@ -1,57 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.ArgumentCommandNode;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.CommandNode;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.LiteralCommandNode;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.RootCommandNode;
import de.kentoj.scrow.bukkit.services.command.exception.CommandSyntaxException;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class BukkitCommand extends Command {
private final RootCommandNode rootCommandNode;
protected BukkitCommand(RootCommandNode rootCommandNode) {
super(rootCommandNode.getName());
this.rootCommandNode = rootCommandNode;
if (rootCommandNode.getDescription() != null) {
super.setDescription(rootCommandNode.getDescription());
}
if (rootCommandNode.getAliases() != null) {
super.setAliases(rootCommandNode.getAliases().stream().toList());
}
// TODO usage string?
}
private void processCommand(@NotNull CommandSender sender, @NotNull String commandLabel,
@NotNull String[] args) throws CommandSyntaxException {
CommandNode node = rootCommandNode;
int argsIndex = 0;
while (node.hasNextNode()) {
if (args.length - 1 < argsIndex) {
if (node)
}
if (node instanceof LiteralCommandNode literal) {
node = literal.getSubNode(args[argsIndex]);
if (node == null) {
throw new CommandSyntaxException("Invalid argument -- " + args[argsIndex])
}
} else if (node instanceof ArgumentCommandNode) {
}
argsIndex++;
}
}
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
return true;
}
}

View file

@ -1,53 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.services.command.CommandExecutor;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.ArgumentCommandNode;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.LiteralCommandNode;
import de.kentoj.scrow.bukkit.services.command.context.CommandContext;
import de.kentoj.scrow.bukkit.services.command.type.EntityArgumentType;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import reactor.core.scheduler.Schedulers;
import java.util.logging.Level;
@SuppressWarnings("DataFlowIssue")
public class CoinsCommand implements CommandExecutor {
public CoinsCommand() {
final ArgumentCommandNode node = null;
node.addArgument("player", EntityArgumentType.player(), CommandContext::getSenderPlayer);
node.setExecutor(this::displayCoins);
final LiteralCommandNode setLiteral;
node.addSubNode(setLiteral);
setLiteral
{
final ArgumentCommandNode specifyPlayerNode = null /* TODO */;
node.addSubNode(specifyPlayerNode);
specifyPlayerNode.addArgument("player", EntityArgumentType.player(), CommandContext::getSenderPlayer);
specifyPlayerNode.setExecutor(this::setCoins);
}
}
private void displayCoins(CommandContext ctx) {
final Player player = ctx.getArg("player");
ScrowAPI.getEconomyService()
.getCoins(player.getUniqueId())
.subscribeOn(Schedulers.boundedElastic())
.publishOn(ScrowAPI.getMinecraftScheduler())
.subscribe(coins -> {
player.sendMessage("You have " + coins + "$");
}, err -> {
player.sendMessage("Error fetching coins: " + err.getMessage());
Bukkit.getLogger().log(Level.SEVERE, "Failed fetching coins for " + player.getUniqueId(), err);
});
}
public void setCoins(CommandContext ctx) {
}
}

View file

@ -0,0 +1,39 @@
package de.kentoj.scrow.bukkit.cmds2;
import com.google.common.base.Preconditions;
import de.kentoj.scrow.bukkit.services.command.cmds2.CommandContext;
import de.kentoj.scrow.bukkit.services.command.exception.CommandInvocationException;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import java.util.Map;
@RequiredArgsConstructor
public class CommandContextImpl implements CommandContext {
@Getter
private final CommandSender sender;
private final Map<String, ?> arguments;
@SuppressWarnings("unchecked")
public <T> T getArg(String name) {
final T value = (T) arguments.get(name);
Preconditions.checkState(value != null, "no value for '" + name + "'-argument");
return value;
}
@Override
public Player getSenderPlayer() {
if (!(sender instanceof Player)) throw new CommandInvocationException("This command can only be used by players");
return (Player) sender;
}
@Override
public Entity getSenderEntity() {
if (!(sender instanceof Entity)) throw new CommandInvocationException("This command can only be used by entities");
return (Entity) sender;
}
}

View file

@ -0,0 +1,31 @@
package de.kentoj.scrow.bukkit.cmds2;
import de.kentoj.scrow.bukkit.cmds2.types.CommandArgumentImpl;
import de.kentoj.scrow.bukkit.cmds2.types.LiteralImpl;
import de.kentoj.scrow.bukkit.cmds2.types.RootLiteralImpl;
import de.kentoj.scrow.bukkit.services.command.cmds2.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.cmds2.CommandContext;
import de.kentoj.scrow.bukkit.services.command.cmds2.CommandFactory;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.Literal;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.RootLiteral;
import de.kentoj.scrow.bukkit.services.command.type.ArgumentType;
import java.util.function.Function;
public class CommandFactoryImpl implements CommandFactory {
@Override
public Literal literal(String name) {
return new LiteralImpl(name);
}
@Override
public RootLiteral root(String name) {
return new RootLiteralImpl(name);
}
@Override
public <T> CommandArgument<T> argument(String name, ArgumentType<T> type, Function<CommandContext, T> defaultValueFun) {
return new CommandArgumentImpl<>(name, type, defaultValueFun);
}
}

View file

@ -1,9 +1,9 @@
package de.kentoj.scrow.bukkit.command.bukkit;
package de.kentoj.scrow.bukkit.cmds2;
import de.kentoj.scrow.bukkit.cmds2.parsing.BukkitCommand;
import de.kentoj.scrow.bukkit.services.command.CommandManager;
import de.kentoj.scrow.bukkit.services.command.node.CommandNode;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.RootLiteral;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandMap;
import org.bukkit.plugin.Plugin;
@ -22,18 +22,8 @@ public class CommandManagerImpl implements CommandManager {
}
@Override
public void register(CommandNode rootCommandNode, Plugin plugin) {
var bukkitCommand = toBukkitCommand(rootCommandNode);
public void register(RootLiteral rootLiteral, Plugin plugin) {
var bukkitCommand = new BukkitCommand(rootLiteral);
commandMap.register(plugin.getName(), bukkitCommand);
}
private Command toBukkitCommand(CommandNode commandNode) {
return new BukkitCommand(
commandNode,
commandNode.getName(),
commandNode.getDescription(),
"",
commandNode.getAliases()
);
}
}

View file

@ -0,0 +1,62 @@
package de.kentoj.scrow.bukkit.cmds2.parsing;
import de.kentoj.scrow.bukkit.services.command.ArgumentReader;
import de.kentoj.scrow.bukkit.services.command.exception.CommandInvocationException;
import java.nio.CharBuffer;
public class ArgumentReaderImpl implements ArgumentReader {
private final CharBuffer buf;
public ArgumentReaderImpl(String string) {
buf = CharBuffer.wrap(string);
}
public ArgumentReaderImpl(String[] args) {
this(String.join(" ", args));
}
@Override
public boolean isEOF() {
return buf.position() >= buf.limit();
}
@Override
public String readWord() {
final var str = new StringBuilder();
while (true) {
if (buf.position() >= buf.limit()) break;
char c = buf.get();
if (c == ' ') break;
str.append(c);
}
return str.toString();
}
@Override
public String readQuotedWord() {
final var str = new StringBuilder();
var quoting = false;
while (true) {
if (buf.position() >= buf.limit()) break;
char c = buf.get();
if (c == '"') quoting = !quoting;
if (c == ' ' && !quoting) break;
str.append(c);
}
if (quoting) throw new CommandInvocationException("Missing matching \" to terminate quote");
return str.toString();
}
@Override
public int getCursor() {
return buf.position();
}
@Override
public void setCursor(int cursor) {
buf.position(cursor);
}
}

View file

@ -0,0 +1,36 @@
package de.kentoj.scrow.bukkit.cmds2.parsing;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.RootLiteral;
import de.kentoj.scrow.bukkit.services.command.exception.CommandInvocationException;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class BukkitCommand extends Command {
private final RootLiteral rootLiteral;
public BukkitCommand(RootLiteral rootLiteral) {
super(rootLiteral.getName());
this.rootLiteral = rootLiteral;
if (rootLiteral.getDescription() != null) {
super.setDescription(rootLiteral.getDescription());
}
if (rootLiteral.getAliases() != null) {
super.setAliases(rootLiteral.getAliases().stream().toList());
}
// TODO usage string?
}
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
try {
new CommandProcessor(sender, new ArgumentReaderImpl(args)).execute(rootLiteral);
} catch (CommandInvocationException syntaxException) {
sender.sendMessage(ChatColor.RED + syntaxException.getMessage());
}
return true;
}
}

View file

@ -0,0 +1,23 @@
package de.kentoj.scrow.bukkit.cmds2.parsing;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.RootLiteral;
import lombok.RequiredArgsConstructor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@RequiredArgsConstructor
public class BukkitTabCompleter implements TabCompleter {
private final RootLiteral rootLiteral;
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return List.of();
}
}

View file

@ -0,0 +1,67 @@
package de.kentoj.scrow.bukkit.cmds2.parsing;
import de.kentoj.scrow.bukkit.cmds2.CommandContextImpl;
import de.kentoj.scrow.bukkit.services.command.ArgumentReader;
import de.kentoj.scrow.bukkit.services.command.cmds2.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.Literal;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.RootLiteral;
import de.kentoj.scrow.bukkit.services.command.exception.CommandInvocationException;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import java.util.HashMap;
import java.util.Map;
@RequiredArgsConstructor
public class CommandProcessor {
private final Map<String, Object> arguments = new HashMap<>();
private final CommandSender sender;
private final ArgumentReader argumentReader;
public void execute(RootLiteral rootLiteral) {
Literal lastLiteral = rootLiteral;
do {
processArguments(lastLiteral);
if (argumentReader.isEOF()) {
if (lastLiteral.getExecutor() == null) throw new CommandInvocationException("Incomplete command -- literal expected");
lastLiteral.getExecutor().execute(new CommandContextImpl(sender, arguments));
return;
}
final var literalName = argumentReader.readWord();
lastLiteral = lastLiteral.getLiteral(literalName);
if (lastLiteral == null) throw new CommandInvocationException("Unknown literal -- " + literalName);
final boolean hasSenderPermission = lastLiteral.getRequiredPermission() == null || sender.hasPermission(lastLiteral.getRequiredPermission());
if (!hasSenderPermission) throw new CommandInvocationException("No permission");
} while (lastLiteral.hasLiteral());
processArguments(lastLiteral);
if (lastLiteral.getExecutor() == null) throw new CommandInvocationException("Incomplete command.");
lastLiteral.getExecutor().execute(new CommandContextImpl(sender, arguments));
}
private void processArguments(Literal node) {
node.getArguments().forEach(arg -> {
Object parsed = parseArgument(arg);
arguments.put(arg.getName(), parsed);
});
}
private <T> Object parseArgument(CommandArgument<T> argument) {
if (argumentReader.isEOF()) {
var defaultValue = argument.getDefaultValue(new CommandContextImpl(sender, arguments));
if (defaultValue == null) throw new CommandInvocationException("Missing argument -- " + argument.getName());
return defaultValue;
}
T value = argument.getType().parseInput(argumentReader);
argument.getType().checkValue(new CommandContextImpl(sender, arguments), value);
return value;
}
}

View file

@ -0,0 +1,34 @@
package de.kentoj.scrow.bukkit.cmds2.types;
import de.kentoj.scrow.bukkit.services.command.cmds2.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.cmds2.CommandContext;
import de.kentoj.scrow.bukkit.services.command.cmds2.SuggestionProvider;
import de.kentoj.scrow.bukkit.services.command.type.ArgumentType;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
@Getter
@RequiredArgsConstructor
public class CommandArgumentImpl<T> implements CommandArgument<T> {
private final String name;
private final ArgumentType<T> type;
private final Function<CommandContext, T> defaultValueFun;
@Setter
private @Nullable SuggestionProvider suggestionProvider;
@Override
public @Nullable T getDefaultValue(CommandContext ctx) {
return defaultValueFun.apply(ctx);
}
public SuggestionProvider getSuggestionProvider() {
if (suggestionProvider == null)
return type::getDefaultSuggestions;
return suggestionProvider;
}
}

View file

@ -0,0 +1,58 @@
package de.kentoj.scrow.bukkit.cmds2.types;
import de.kentoj.scrow.bukkit.services.command.CommandExecutor;
import de.kentoj.scrow.bukkit.services.command.cmds2.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.Literal;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.permissions.Permission;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Getter
public class LiteralImpl implements Literal {
@Setter
private String name;
@Setter
private @Nullable Permission requiredPermission = null;
@Setter
private @Nullable String description = null;
@Setter
private @Nullable CommandExecutor executor = null;
private final List<CommandArgument<?>> arguments = new ArrayList<>();
private final Map<String, Literal> literals = new HashMap<>();
public LiteralImpl(String name) {
this.name = name;
}
@Override
public void addLiteral(Literal node) {
if (literals.containsKey(node.getName())) {
Bukkit.getLogger().warning("Literal " + node.getName() + " is overwritten by literal with same name");
}
literals.put(node.getName(), node);
}
@Override
public @Nullable Literal getLiteral(String name) {
return literals.get(name);
}
@Override
public boolean hasLiteral() {
return !literals.isEmpty();
}
@Override
public <T> void addArgument(CommandArgument<T> argument) {
arguments.add(argument);
}
}

View file

@ -0,0 +1,25 @@
package de.kentoj.scrow.bukkit.cmds2.types;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.RootLiteral;
import lombok.Getter;
import lombok.Setter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class RootLiteralImpl extends LiteralImpl implements RootLiteral {
@Getter
@Setter
private Set<String> aliases = new HashSet<>();
public RootLiteralImpl(String name) {
super(name);
}
@Override
public void addAliases(String... aliases) {
this.aliases.addAll(List.of(aliases));
}
}

View file

@ -1,25 +0,0 @@
package de.kentoj.scrow.bukkit.command;
import de.kentoj.scrow.bukkit.services.command.context.CommandContext;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@RequiredArgsConstructor
public class CommandContextImpl implements CommandContext {
@Getter
private final CommandSender sender;
@Override
public Player getSenderPlayer() {
return (Player) sender;
}
@Override
public Entity getSenderEntity() {
return (Entity) sender;
}
}

View file

@ -1,48 +0,0 @@
package de.kentoj.scrow.bukkit.command;
import de.kentoj.scrow.bukkit.command.bukkit.ArgumentData;
import de.kentoj.scrow.bukkit.services.command.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.exception.CommandSyntaxException;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
public class CommandExecutionContextImpl extends CommandContextImpl implements CommadContext {
private final Map<String, ArgumentData> argumentDataMap;
public CommandExecutionContextImpl(CommandSender sender, Map<String, ArgumentData> argumentDataMap) {
super(sender);
this.argumentDataMap = argumentDataMap;
}
@Override
public @Nullable String getRawArgument(String key) {
var data = argumentDataMap.get(key);
if (data.getRawValue() == null) {
if (data.getArgument().getDefaultValue() == null) {
throw new CommandSyntaxException("usage: missing arg value for " + key);
}
return null;
}
return data.getRawValue();
}
@SuppressWarnings("unchecked")
public <T> T getArg(String key) {
var data = argumentDataMap.get(key);
var arg = (CommandArgument<T>) data.getArgument();
var raw = getRawArgument(key);
T value;
if (raw != null) {
value = arg.getType().parseInput(raw);
} else {
value = arg.getDefaultValue().apply(this);
}
arg.getType().checkValue(this, value, raw);
return value;
}
}

View file

@ -1,11 +0,0 @@
package de.kentoj.scrow.bukkit.command.bukkit;
import de.kentoj.scrow.bukkit.services.command.CommandArgument;
import lombok.Value;
import org.jetbrains.annotations.Nullable;
@Value
public class ArgumentData {
CommandArgument<?> argument;
@Nullable String rawValue;
}

View file

@ -1,34 +0,0 @@
package de.kentoj.scrow.bukkit.command.bukkit;
import de.kentoj.scrow.bukkit.services.command.exception.CommandSyntaxException;
import de.kentoj.scrow.bukkit.services.command.node.CommandNode;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
public class BukkitCommand extends Command {
private final CommandNode rootCommandNode;
protected BukkitCommand(CommandNode rootCommandNode, @NotNull String name, @NotNull String description, @NotNull String usageMessage, @NotNull Set<String> aliases) {
super(name, description, usageMessage, aliases.stream().toList());
this.rootCommandNode = rootCommandNode;
}
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
final var commandProcessor = new CommandProcessor(rootCommandNode, sender, args);
try {
commandProcessor.process();
} catch (CommandSyntaxException e) {
sender.sendMessage("error: " + e.getMessage());
return true;
} catch (IllegalStateException e) {
throw new RuntimeException("failed processing command " + rootCommandNode.getName(), e);
}
return true;
}
}

View file

@ -1,62 +0,0 @@
package de.kentoj.scrow.bukkit.command.bukkit;
import de.kentoj.scrow.bukkit.command.CommandExecutionContextImpl;
import de.kentoj.scrow.bukkit.services.command.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.CommandExecutor;
import de.kentoj.scrow.bukkit.services.command.context.CommandContext;
import de.kentoj.scrow.bukkit.services.command.exception.CommandSyntaxException;
import de.kentoj.scrow.bukkit.services.command.node.CommandNode;
import de.kentoj.scrow.bukkit.services.command.node.CommandNodeWithArguments;
import de.kentoj.scrow.bukkit.services.command.node.CommandNodeWithSubCommand;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@AllArgsConstructor
public class CommandProcessor {
private final Map<String, ArgumentData> argumentDataMap = new HashMap<>();
private CommandNode node;
private final CommandSender sender;
private final String[] args;
public void process() throws CommandSyntaxException {
for (int cursor = 0; true; cursor++) {
if (args.length - 1 < cursor) {
if (node.getExecutor() == null) throw new CommandSyntaxException("Incomplete command");
execute(node.getExecutor());
return;
}
if (node instanceof CommandNodeWithArguments nodeWA) {
final var arg = nodeWA.getArg(cursor);
assert arg != null;
final var data = new ArgumentData(arg, args[cursor]);
argumentDataMap.put(arg.getName(), data);
} else if (node instanceof CommandNodeWithSubCommand nodeWS) {
if (nodeWS.getSubCommands().isEmpty()) break;
final var subcommand = nodeWS.getSubCommand(args[cursor]);
if (subcommand == null) {
final var subcommands = nodeWS.getSubCommands().stream().map(CommandNode::getName).toList();
throw new CommandSyntaxException("Illegal argument -- " + args[cursor] + "\nExpected arguments: " + String.join(", ", subcommands));
}
this.node = nodeWS;
}
}
if (node.getExecutor() == null) throw new IllegalStateException("Last CommandNode must have an executor");
execute(node.getExecutor());
}
private void execute(CommandExecutor executor) {
var ctx = new CommandExecutionContextImpl(sender, argumentDataMap);
executor.execute(ctx);
}
}

View file

@ -1,23 +0,0 @@
package de.kentoj.scrow.bukkit.command.node;
import de.kentoj.scrow.bukkit.services.command.node.CommandNode;
import de.kentoj.scrow.bukkit.services.command.node.CommandNodeFactory;
import de.kentoj.scrow.bukkit.services.command.node.CommandNodeWithArguments;
import de.kentoj.scrow.bukkit.services.command.node.CommandNodeWithSubCommand;
public class CommandNodeFactoryImpl implements CommandNodeFactory {
@Override
public CommandNodeWithSubCommand createNodeWithSubCommands(String name) {
return new CommandNodeWithSubCommandImpl(name);
}
@Override
public CommandNodeWithArguments createNodeWithArguments(String name) {
return new CommandNodeWithArgumentsImpl(name);
}
@Override
public CommandNode createRootNode(String name) {
return new CommandNodeImpl(name);
}
}

View file

@ -1,36 +0,0 @@
package de.kentoj.scrow.bukkit.command.node;
import de.kentoj.scrow.bukkit.services.command.CommandExecutor;
import de.kentoj.scrow.bukkit.services.command.node.CommandNode;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.permissions.Permission;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@Getter
public class CommandNodeImpl implements CommandNode {
private final String name;
@Setter
private Set<String> aliases = new HashSet<>();
@Setter
private @Nullable Permission permission = null;
@Setter
private @Nullable String description;
@Setter
private @Nullable CommandExecutor executor = null;
public CommandNodeImpl(String name) {
this.name = name;
}
@Override
public void addAlias(String... aliases) {
this.aliases.addAll(Arrays.asList(aliases));
}
}

View file

@ -1,50 +0,0 @@
package de.kentoj.scrow.bukkit.command.node;
import de.kentoj.scrow.bukkit.services.command.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.context.CommandContext;
import de.kentoj.scrow.bukkit.services.command.node.CommandNodeWithArguments;
import de.kentoj.scrow.bukkit.services.command.type.ArgumentType;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class CommandNodeWithArgumentsImpl extends CommandNodeImpl implements CommandNodeWithArguments {
private final List<CommandArgument<?>> args = new ArrayList<>();
public CommandNodeWithArgumentsImpl(String name) {
super(name);
}
@Override
public <T> void addArg(String name, ArgumentType<T> type, Function<CommandContext, T> defaultValue) {
var index = args.size();
if (index > 0) {
boolean isPreviousArgumentOptional = args.get(index - 1).getDefaultValue() != null;
boolean isNewArgumentOptional = defaultValue != null;
if (isPreviousArgumentOptional && !isNewArgumentOptional) {
throw new IllegalStateException("an optional argument(an argument with a defaultValue set) may not be followed by a required argument");
}
}
args.add(new CommandArgument<>(index, name, type, defaultValue));
}
@Override
public @Nullable CommandArgument<?> getArg(String name) {
return args.stream()
.filter(ra -> ra.getName().equals(name))
.findFirst()
.orElse(null);
}
@Override
public @Nullable CommandArgument<?> getArg(int index) {
return args.stream()
.filter(ra -> ra.getIndex() == index)
.findFirst()
.orElse(null);
}
}

View file

@ -1,32 +0,0 @@
package de.kentoj.scrow.bukkit.command.node;
import de.kentoj.scrow.bukkit.services.command.node.CommandNode;
import de.kentoj.scrow.bukkit.services.command.node.CommandNodeWithSubCommand;
import lombok.Getter;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class CommandNodeWithSubCommandImpl extends CommandNodeImpl implements CommandNodeWithSubCommand {
@Getter
private final List<CommandNode> subCommands = new ArrayList<>();
public CommandNodeWithSubCommandImpl(String name) {
super(name);
}
@Override
public void addSubCommand(CommandNode subCommand) {
subCommands.add(subCommand);
}
@Override
public @Nullable CommandNode getSubCommand(String label) {
return subCommands.stream()
.filter(n -> n.getName().equals(label) || n.getAliases().contains(label))
.findFirst()
.orElse(null);
}
}

View file

@ -14,6 +14,7 @@ import reactor.core.publisher.Mono;
import java.util.UUID;
// TODO log
public class MongoEconomyService implements EconomyService {
private static final String COLLECTION_NAME = "economy";

View file

@ -0,0 +1,86 @@
package de.kentoj.scrow.bukkit.economy.command;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.services.command.cmds2.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.cmds2.CommandContext;
import de.kentoj.scrow.bukkit.services.command.cmds2.Commands;
import de.kentoj.scrow.bukkit.services.command.cmds2.node.RootLiteral;
import de.kentoj.scrow.bukkit.services.command.type.NumberArgumentType;
import de.kentoj.scrow.bukkit.services.command.type.PlayerArgumentType;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import reactor.core.scheduler.Schedulers;
import java.util.logging.Level;
public class CoinsCommand {
private final RootLiteral rootCommand;
private final CommandArgument<OfflinePlayer> playerArg;
private final CommandArgument<Integer> amountArg;
/*
/coins steve
/coins steve set 0
/coins steve get
*/
public CoinsCommand() {
playerArg = Commands.argument0("player", PlayerArgumentType.offlinePlayer(), CommandContext::getSenderPlayer);
amountArg = Commands.argument0("amount", NumberArgumentType.integer(0, Integer.MAX_VALUE));
rootCommand = Commands.root("coins");
rootCommand.addArgument(playerArg);
rootCommand.setExecutor(this::getCoins);
{
final var setLiteral = Commands.literal("set");
setLiteral.addArgument(amountArg);
setLiteral.setExecutor(this::setCoins);
rootCommand.addLiteral(setLiteral);
}
{
final var getLiteral = Commands.literal("get");
getLiteral.setExecutor(this::getCoins);
rootCommand.addLiteral(getLiteral);
}
}
public RootLiteral create() {
return rootCommand;
}
private void getCoins(CommandContext ctx) {
final var player = ctx.getArg(playerArg);
ScrowAPI.getEconomyService()
.getCoins(player.getUniqueId())
.subscribeOn(Schedulers.boundedElastic())
.publishOn(ScrowAPI.getMinecraftScheduler())
.subscribe(amount -> {
if (player == ctx.getSender()) {
ctx.getSender().sendMessage("You have " + amount + "$");
} else {
ctx.getSender().sendMessage(player.getName() + " has " + amount + "$");
}
}, err -> {
ctx.getSender().sendMessage("Unable to get coins: " + err.getMessage());
Bukkit.getLogger().log(Level.SEVERE, "Unable to get coins of " + player.getUniqueId(), err);
});
}
public void setCoins(CommandContext ctx) {
final var player = ctx.getArg(playerArg);
final int amount = ctx.getArg(amountArg);
ScrowAPI.getEconomyService()
.setCoins(player.getUniqueId(), amount)
.subscribeOn(Schedulers.boundedElastic())
.publishOn(ScrowAPI.getMinecraftScheduler())
.subscribe(__ -> {
ctx.getSender().sendMessage(player.getName() + " now has " + amount + "$");
}, err -> {
ctx.getSender().sendMessage("Unable to set coins: " + err.getMessage());
Bukkit.getLogger().log(Level.SEVERE, "Unable to set coins of " + player.getUniqueId() + " to " + amount, err);
});
}
}

View file

@ -1,13 +0,0 @@
package de.kentoj.scrow.bukkit.friends.command;
import de.kentoj.scrow.bukkit.services.command.node.CommandNodeRepository;
import de.kentoj.scrow.bukkit.services.command.node.CommandNodeWithSubCommand;
public class FriendCommand {
private final CommandNodeWithSubCommand node = CommandNodeRepository.withSubCommands("friend");
public FriendCommand() {
this.node.addAlias("f");
}
}

View file

@ -1,30 +0,0 @@
package de.kentoj.scrow.bukkit.friends.command;
import de.kentoj.scrow.bukkit.command.node.CommandNodeWithArgumentsImpl;
import de.kentoj.scrow.bukkit.services.command.CommandExecutor;
import de.kentoj.scrow.bukkit.services.command.context.CommandContext;
import de.kentoj.scrow.bukkit.services.command.type.EntityArgumentType;
import net.md_5.bungee.api.chat.TranslatableComponent;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.util.Vector;
public class LaunchCommand extends CommandNodeWithArgumentsImpl implements CommandExecutor {
public LaunchCommand() {
super("launch");
this.setDescription("launches a player in the air");
this.setPermission(new Permission("bukkitcore.cmd.launch"));
this.addArg("player", EntityArgumentType.player(), CommandContext::getSenderPlayer);
this.setExecutor(this);
}
@Override
public void execute(CommandExecutionContext ctx) {
final Player player = ctx.getArg("player");
player.spigot().sendMessage(new TranslatableComponent(""));
player.setVelocity(new Vector(0, 2, 0));
player.sendMessage("Launched " + player.getName() + ".");
}
}