This commit is contained in:
kento2 2026-04-15 21:45:19 +02:00
parent 179f94085f
commit 3345595146
52 changed files with 95 additions and 905 deletions

View file

@ -1,3 +1,6 @@
val scrowToken = providers.gradleProperty("scrowMavenToken")
.orElse(providers.environmentVariable("SCROW_MAVEN_TOKEN")).get()
plugins {
id("java")
id("io.freefair.lombok") version "9.2.0" apply false
@ -19,6 +22,18 @@ subprojects {
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") {
name = "spigotmc-repo"
}
maven {
name = "scrow"
url = uri("http://forge.kentoj.de/api/packages/scrow/maven")
isAllowInsecureProtocol = true
credentials(HttpHeaderCredentials::class) {
name = "Authorization"
value = "token $scrowToken"
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
dependencies {
@ -26,7 +41,7 @@ subprojects {
implementation("org.jetbrains:annotations:26.0.2-1")
// https://projectreactor.io/docs/core/release/reference/gettingStarted.html
implementation(platform("io.projectreactor:reactor-bom:2025.0.3"))
implementation(platform("io.projectreactor:reactor-bom:2025.0.3"))
implementation("io.projectreactor:reactor-core")
// https://mvnrepository.com/artifact/com.google.guava/guava

View file

@ -1,4 +1,5 @@
import org.gradle.internal.declarativedsl.dom.mutation.valueFromString
val scrowToken = providers.gradleProperty("scrowMavenToken")
.orElse(providers.environmentVariable("SCROW_MAVEN_TOKEN"))
plugins {
id("java")
@ -11,6 +12,20 @@ version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
maven {
name = "scrow"
url = uri("http://forge.kentoj.de/api/packages/scrow/maven")
isAllowInsecureProtocol = true
credentials(HttpHeaderCredentials::class) {
name = "Authorization"
value = "token $scrowToken"
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
dependencies {
@ -20,33 +35,19 @@ dependencies {
api("org.spigotmc:spigot-api:1.21.11-R0.1-SNAPSHOT")
api("net.kyori:adventure-platform-bukkit:4.4.1")
api("de.kentoj:kencommandapi-core:1.0.0")
}
publishing {
publications {
create<MavenPublication>("CoreBukkitApi") {
create<MavenPublication>("ScrowBukkitApi") {
groupId = project.group.toString()
artifactId = project.name
version = project.version.toString()
from(components["java"])
}
}
repositories {
maven {
name = "scrow"
url = uri("http://forge.kentoj.de/api/packages/scrow/maven")
isAllowInsecureProtocol = true
credentials(HttpHeaderCredentials::class) {
name = "Authorization"
value = "token a967694822eed6e97b1b20e8737733ef1400fa1f"
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}
tasks.test {

View file

@ -1,4 +1,4 @@
package de.kentoj.scrow.bukkit.services;
package de.kentoj.scrow.bukkit;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;

View file

@ -1,12 +1,15 @@
package de.kentoj.scrow.bukkit;
import com.mongodb.reactivestreams.client.MongoDatabase;
import de.kentoj.scrow.bukkit.services.EconomyService;
import de.kentoj.scrow.bukkit.services.command.CommandManager;
import de.kentoj.scrow.bukkit.services.friends.FriendsService;
import de.kentoj.kencommandapi.api.KenCommandApi;
import de.kentoj.kencommandapi.api.processing.CommandContext;
import de.kentoj.kencommandapi.api.structure.node.CommandNode;
import de.kentoj.scrow.bukkit.friends.FriendsService;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import reactor.core.scheduler.Scheduler;
@ -17,7 +20,7 @@ public class ScrowAPI {
@Getter
private static @Nullable MongoDatabase database;
@Getter
private static CommandManager commandManager;
private static KenCommandApi<CommandSender, CommandContext<CommandSender>> commandManager;
@Getter
private static Scheduler minecraftScheduler;
@Getter
@ -36,7 +39,7 @@ public class ScrowAPI {
}
@ApiStatus.Internal
public static void setCommandManager(CommandManager commandManager) {
public static void setCommandManager(KenCommandApi<CommandSender, CommandContext<CommandSender>> commandManager) {
ScrowAPI.commandManager = commandManager;
}

View file

@ -1,4 +1,4 @@
package de.kentoj.scrow.bukkit.services.email;
package de.kentoj.scrow.bukkit.email;
import org.jetbrains.annotations.Nullable;

View file

@ -1,4 +1,4 @@
package de.kentoj.scrow.bukkit.services.email;
package de.kentoj.scrow.bukkit.email;
import org.jetbrains.annotations.Nullable;

View file

@ -1,4 +1,4 @@
package de.kentoj.scrow.bukkit.services.email;
package de.kentoj.scrow.bukkit.email;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Flux;

View file

@ -1,4 +1,4 @@
package de.kentoj.scrow.bukkit.services.friends;
package de.kentoj.scrow.bukkit.friends;
import java.time.Instant;
import java.util.UUID;

View file

@ -1,4 +1,4 @@
package de.kentoj.scrow.bukkit.services.friends;
package de.kentoj.scrow.bukkit.friends;
public class FriendRequestUsageException extends RuntimeException {

View file

@ -1,4 +1,4 @@
package de.kentoj.scrow.bukkit.services.friends;
package de.kentoj.scrow.bukkit.friends;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Flux;

View file

@ -1,4 +1,4 @@
package de.kentoj.scrow.bukkit.services.friends;
package de.kentoj.scrow.bukkit.friends;
import de.kentoj.scrow.bukkit.util.pair.Tuple2;

View file

@ -1,18 +0,0 @@
package de.kentoj.scrow.bukkit.services.command;
import de.kentoj.scrow.bukkit.services.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.services.command.literal.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.literal.Literal;
import de.kentoj.scrow.bukkit.services.command.literal.RootLiteral;
import de.kentoj.scrow.bukkit.services.command.type.ArgumentType;
import java.util.function.Function;
public interface CommandFactory {
Literal literal(String name);
RootLiteral root(String name);
<T> CommandArgument<T> argument(String name, ArgumentType<T> type, Function<CommandContext, T> defaultValueFun);
}

View file

@ -1,9 +0,0 @@
package de.kentoj.scrow.bukkit.services.command;
import de.kentoj.scrow.bukkit.services.command.literal.RootLiteral;
import org.bukkit.plugin.Plugin;
public interface CommandManager {
void register(RootLiteral rootLiteral, Plugin plugin);
}

View file

@ -1,43 +0,0 @@
package de.kentoj.scrow.bukkit.services.command;
import de.kentoj.scrow.bukkit.services.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.services.command.literal.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.literal.Literal;
import de.kentoj.scrow.bukkit.services.command.literal.RootLiteral;
import de.kentoj.scrow.bukkit.services.command.type.ArgumentType;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.ApiStatus;
import java.util.function.Function;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Commands {
private static CommandFactory factory;
public static Literal literal(String name) {
return factory.literal(name);
}
public static RootLiteral root(String name) {
return factory.root(name);
}
public static <T> CommandArgument<T> argument0(String name, ArgumentType<T> type, Function<CommandContext, T> defaultValueFun) {
return factory.argument(name, type, defaultValueFun);
}
public static <T> CommandArgument<T> argument1(String name, ArgumentType<T> type, T defaultValue) {
return factory.argument(name, type, __ -> defaultValue);
}
public static <T> CommandArgument<T> argument0(String name, ArgumentType<T> type) {
return factory.argument(name, type, __ -> null);
}
@ApiStatus.Internal
public static void setFactory(CommandFactory factory) {
Commands.factory = factory;
}
}

View file

@ -1,10 +0,0 @@
package de.kentoj.scrow.bukkit.services.command;
import de.kentoj.scrow.bukkit.services.command.execution.CommandContext;
import java.util.Set;
public interface SuggestionProvider {
Set<String> suggest(CommandContext context);
}

View file

@ -1,22 +0,0 @@
package de.kentoj.scrow.bukkit.services.command.exception;
/**
* When a command has a syntax issue.
* {@code CommandSyntaxException::getMessage} should return a user-friendly message explaining the issue.
*/
public class CommandInvocationException extends RuntimeException {
/**
* @param message user-friendly message
*/
public CommandInvocationException(String message) {
super(message);
}
/**
* @param message user-friendly message
*/
public CommandInvocationException(String message, Throwable throwable) {
super(message + ": " + throwable.getMessage());
}
}

View file

@ -1,16 +0,0 @@
package de.kentoj.scrow.bukkit.services.command.execution;
import de.kentoj.scrow.bukkit.services.command.literal.CommandArgument;
import org.jetbrains.annotations.Nullable;
public interface ArgumentData<T> {
T getValue();
CommandArgument<T> getArgument();
/**
* @return null if the default value for the type was used
*/
@Nullable String getRawInput();
}

View file

@ -1,37 +0,0 @@
package de.kentoj.scrow.bukkit.services.command.execution;
import de.kentoj.scrow.bukkit.services.command.exception.CommandInvocationException;
import de.kentoj.scrow.bukkit.services.command.literal.CommandArgument;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
public interface CommandContext {
CommandSender getSender();
Player getSenderPlayer();
Entity getSenderEntity();
/**
* @return Object that is parsed from the raw argument
* @throws CommandInvocationException if no value given and no default value supplied
*/
<T> ArgumentData<T> getArgData(String name);
@SuppressWarnings("unchecked")
default <T> T getArgData(CommandArgument<T> arg) {
return (T) getArgData(arg.getName());
}
@SuppressWarnings("unchecked")
default <T> T getArg(String name) {
return (T) getArgData(name).getValue();
}
@SuppressWarnings("unchecked")
default <T> T getArg(CommandArgument<T> arg) {
return (T) getArgData(arg.getName()).getValue();
}
}

View file

@ -1,8 +0,0 @@
package de.kentoj.scrow.bukkit.services.command.execution;
import de.kentoj.scrow.bukkit.services.command.exception.CommandInvocationException;
public interface CommandExecutor {
void execute(CommandContext ctx) throws CommandInvocationException;
}

View file

@ -1,14 +0,0 @@
package de.kentoj.scrow.bukkit.services.command.literal;
public interface ArgumentReader {
boolean isEOF();
String readWord();
String readQuotedWord();
int getCursor();
void setCursor(int cursor);
}

View file

@ -1,22 +0,0 @@
package de.kentoj.scrow.bukkit.services.command.literal;
import de.kentoj.scrow.bukkit.services.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.services.command.SuggestionProvider;
import de.kentoj.scrow.bukkit.services.command.type.ArgumentType;
import org.jetbrains.annotations.Nullable;
public interface CommandArgument<T> {
String getName();
ArgumentType<T> getType();
@Nullable T getDefaultValue(CommandContext ctx);
void setSuggestionProvider(@Nullable SuggestionProvider suggestionProvider);
/**
* @return the explicitly set SuggestionProvider or the suggestions for the type if unset/null
*/
SuggestionProvider getSuggestionProvider();
}

View file

@ -1,45 +0,0 @@
package de.kentoj.scrow.bukkit.services.command.literal;
import de.kentoj.scrow.bukkit.services.command.execution.CommandExecutor;
import org.bukkit.permissions.Permission;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Set;
public interface Literal {
/**
* String with no spaces!
*/
void setName(String name);
/**
* String with no spaces!
*/
String getName();
void addLiteral(Literal node);
@Nullable Literal getLiteral(String rawArg);
Set<Literal> getLiterals();
boolean hasLiteral();
void setExecutor(@Nullable CommandExecutor executor);
@Nullable CommandExecutor getExecutor();
void setDescription(@Nullable String description);
@Nullable String getDescription();
Permission getRequiredPermission();
void setRequiredPermission(Permission permission);
<T> void addArgument(CommandArgument<T> argument);
List<CommandArgument<?>> getArguments();
}

View file

@ -1,12 +0,0 @@
package de.kentoj.scrow.bukkit.services.command.literal;
import java.util.Set;
public interface RootLiteral extends Literal {
Set<String> getAliases();
void setAliases(Set<String> aliases);
void addAliases(String... aliases);
}

View file

@ -1,21 +0,0 @@
package de.kentoj.scrow.bukkit.services.command.type;
import de.kentoj.scrow.bukkit.services.command.literal.ArgumentReader;
import de.kentoj.scrow.bukkit.services.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.services.command.exception.CommandInvocationException;
import java.util.Set;
public interface ArgumentType<T> {
T parseInput(String rawInput);
String readRawInput(ArgumentReader reader);
/**
* @throws CommandInvocationException if the given value may not be used
*/
void checkValue(CommandContext ctx, T value, String rawInput) throws CommandInvocationException;
Set<String> getDefaultSuggestions(CommandContext ctx);
}

View file

@ -1,47 +0,0 @@
package de.kentoj.scrow.bukkit.services.command.type;
import com.google.common.base.Preconditions;
import de.kentoj.scrow.bukkit.services.command.literal.ArgumentReader;
import de.kentoj.scrow.bukkit.services.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.services.command.exception.CommandInvocationException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.Set;
// TODO add livingEntity
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class NumberArgumentType {
public static ArgumentType<Integer> integer(int min, int max) {
Preconditions.checkArgument(min < max, "min is greater than max");
return new ArgumentType<>() {
@Override
public Integer parseInput(String rawInput) {
try {
return Integer.parseInt(rawInput);
} catch (NumberFormatException ex) {
throw new CommandInvocationException("Invalid number -- " + rawInput);
}
}
@Override
public String readRawInput(ArgumentReader reader) {
return reader.readWord();
}
@Override
public void checkValue(CommandContext ctx, Integer value, String rawInput) throws CommandInvocationException {
if (value < min) throw new CommandInvocationException("Value too small -- " + value);
if (value > max) throw new CommandInvocationException("Value too large -- " + value);
}
@Override
public Set<String> getDefaultSuggestions(CommandContext ctx) {
return Set.of();
}
};
}
}

View file

@ -1,89 +0,0 @@
package de.kentoj.scrow.bukkit.services.command.type;
import de.kentoj.scrow.bukkit.services.command.literal.ArgumentReader;
import de.kentoj.scrow.bukkit.services.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.services.command.exception.CommandInvocationException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
// TODO add livingEntity
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class PlayerArgumentType {
private static final ArgumentType<Player> player = new ArgumentType<>() {
@Override
public Player parseInput(String rawInput) {
if (rawInput.length() == 36) {
var uuid = UUID.fromString(rawInput);
return Bukkit.getPlayer(uuid);
} else {
return Bukkit.getPlayerExact(rawInput);
}
}
@Override
public String readRawInput(ArgumentReader reader) {
return reader.readWord();
}
@Override
public void checkValue(CommandContext ctx, Player value, String rawInput) throws CommandInvocationException {
if (value == null) throw new CommandInvocationException("Player is not online -- " + rawInput);
}
@Override
public Set<String> getDefaultSuggestions(CommandContext ctx) {
return Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toSet());
}
};
private static final ArgumentType<OfflinePlayer> offlinePlayer = new ArgumentType<>() {
@Override
public OfflinePlayer parseInput(String rawInput) {
OfflinePlayer player;
player = Bukkit.getPlayerExact(rawInput);
if (player == null) {
try {
player = Bukkit.getOfflinePlayer(UUID.fromString(rawInput));
} catch (IllegalArgumentException ex) {
throw new CommandInvocationException("Not a UUID or name of an online player -- " + rawInput);
}
}
return player;
}
@Override
public String readRawInput(ArgumentReader reader) {
return reader.readWord();
}
@Override
public Set<String> getDefaultSuggestions(CommandContext ctx) {
return Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toSet());
}
@Override
public void checkValue(CommandContext ctx, OfflinePlayer value, String rawInput) throws CommandInvocationException {
if (!value.hasPlayedBefore()) throw new CommandInvocationException("Player has never played before -- " + rawInput);
}
};
public static ArgumentType<Player> player() {
return player;
}
public static ArgumentType<OfflinePlayer> offlinePlayer() {
return offlinePlayer;
}
}

View file

@ -18,8 +18,11 @@ dependencies {
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
implementation(project(":core-bukkit-api"))
implementation(kotlin("stdlib-jdk8"))
implementation(project(":core-bukkit-api"))
implementation("org.spigotmc:spigot-api:1.21.11-R0.1-SNAPSHOT")
implementation("de.kentoj:kencommandapi-bukkit:1.0.0")
}
tasks {

View file

@ -1,5 +1,6 @@
package de.kentoj.scrow.bukkit;
import de.kentoj.kencommandapi.BukkitKenCommandApi;
import de.kentoj.scrow.bukkit.economy.CoinsCommand;
import de.kentoj.scrow.bukkit.friends.command.FriendCommand;
import org.bukkit.plugin.java.JavaPlugin;
@ -14,6 +15,7 @@ public class CoreImplPlugin extends JavaPlugin {
ScrowAPISurface.initScrowAPI(this, false);
{
BukkitKenCommandApi kenCommandApi = new BukkitKenCommandApi();
ScrowAPI.getCommandManager().register(new CoinsCommand().create(), this);
ScrowAPI.getCommandManager().register(new FriendCommand().create(), this);
}

View file

@ -4,11 +4,12 @@ import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import de.kentoj.kencommandapi.BukkitKenCommandApi;
import de.kentoj.scrow.bukkit.cmds2.CommandFactoryImpl;
import de.kentoj.scrow.bukkit.cmds2.bukkit.BukkitCommandManager;
import de.kentoj.scrow.bukkit.economy.InMemoryEconomyService;
import de.kentoj.scrow.bukkit.economy.MongoEconomyService;
import de.kentoj.scrow.bukkit.services.command.Commands;
import de.kentoj.scrow.bukkit.command.Commands;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.bson.UuidRepresentation;
@ -47,9 +48,10 @@ public class ScrowAPISurface {
ScrowAPI.getDatabase() != null ?
new MongoEconomyService(ScrowAPI.getDatabase()) : new InMemoryEconomyService()
);
ScrowAPI.setCommandManager(new BukkitKenCommandApi());
// TODO friends service
Commands.setFactory(new CommandFactoryImpl());
ScrowAPI.setCommandManager(new BukkitCommandManager());
}
public static void destroyScrowAPI() {

View file

@ -1,34 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2;
import de.kentoj.scrow.bukkit.services.command.literal.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.services.command.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

@ -1,40 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2;
import com.google.common.base.Preconditions;
import de.kentoj.scrow.bukkit.services.command.execution.ArgumentData;
import de.kentoj.scrow.bukkit.services.command.execution.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, ArgumentData<?>> arguments;
@SuppressWarnings("unchecked")
public <T> ArgumentData<T> getArgData(String name) {
final var data = (ArgumentData<T>) arguments.get(name);
Preconditions.checkState(data != null, "no data for '" + name + "'-argument");
return data;
}
@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

@ -1,28 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2;
import de.kentoj.scrow.bukkit.services.command.literal.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.services.command.CommandFactory;
import de.kentoj.scrow.bukkit.services.command.literal.Literal;
import de.kentoj.scrow.bukkit.services.command.literal.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,60 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2;
import de.kentoj.scrow.bukkit.services.command.execution.CommandExecutor;
import de.kentoj.scrow.bukkit.services.command.literal.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.literal.Literal;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.permissions.Permission;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@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 Set<Literal> getLiterals() {
return new HashSet<>(literals.values());
}
@Override
public <T> void addArgument(CommandArgument<T> argument) {
arguments.add(argument);
}
}

View file

@ -1,25 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2;
import de.kentoj.scrow.bukkit.services.command.literal.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,38 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2.bukkit;
import de.kentoj.scrow.bukkit.cmds2.parsing.ArgumentReaderImpl;
import de.kentoj.scrow.bukkit.cmds2.parsing.CommandProcessor;
import de.kentoj.scrow.bukkit.services.command.literal.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

@ -1,28 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2.bukkit;
import de.kentoj.scrow.bukkit.services.command.CommandManager;
import de.kentoj.scrow.bukkit.services.command.literal.RootLiteral;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandMap;
import org.bukkit.plugin.Plugin;
public class BukkitCommandManager implements CommandManager {
private final CommandMap commandMap;
public BukkitCommandManager() {
try {
var field = Bukkit.getPluginManager().getClass().getDeclaredField("commandMap");
field.setAccessible(true);
commandMap = (CommandMap) field.get(Bukkit.getPluginManager());
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@Override
public void register(RootLiteral rootLiteral, Plugin plugin) {
var bukkitCommand = new BukkitCommand(rootLiteral);
commandMap.register(plugin.getName(), bukkitCommand);
}
}

View file

@ -1,23 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2.bukkit;
import de.kentoj.scrow.bukkit.services.command.literal.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

@ -1,13 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2.parsing;
import de.kentoj.scrow.bukkit.services.command.execution.ArgumentData;
import de.kentoj.scrow.bukkit.services.command.literal.CommandArgument;
import lombok.Value;
import org.jetbrains.annotations.Nullable;
@Value
public class ArgumentDataImpl<T> implements ArgumentData<T> {
T value;
CommandArgument<T> argument;
@Nullable String rawInput;
}

View file

@ -1,62 +0,0 @@
package de.kentoj.scrow.bukkit.cmds2.parsing;
import de.kentoj.scrow.bukkit.services.command.literal.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;
final 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;
final 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

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

View file

@ -1,30 +1,41 @@
package de.kentoj.scrow.bukkit.economy;
import de.kentoj.kencommandapi.BukkitKenCommandApi;
import de.kentoj.kencommandapi.api.processing.CommandContext;
import de.kentoj.kencommandapi.api.structure.argument.types.IntegerArgumentType;
import de.kentoj.kencommandapi.api.structure.node.CommandNode;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.services.command.literal.CommandArgument;
import de.kentoj.scrow.bukkit.services.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.services.command.Commands;
import de.kentoj.scrow.bukkit.services.command.literal.RootLiteral;
import de.kentoj.scrow.bukkit.services.command.type.NumberArgumentType;
import de.kentoj.scrow.bukkit.services.command.type.PlayerArgumentType;
import de.kentoj.scrow.bukkit.command.Commands;
import de.kentoj.scrow.bukkit.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.command.literal.CommandArgument;
import de.kentoj.scrow.bukkit.command.literal.RootLiteral;
import de.kentoj.scrow.bukkit.command.type.NumberArgumentType;
import de.kentoj.scrow.bukkit.command.type.PlayerArgumentType;
import lombok.var;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
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;
public void create() {
var rootCommand = ScrowAPI.getCommandManager().createNode("coins");
var playerArg = ScrowAPI.getCommandManager().createArgument("player", )
}
/*
/coins steve
/coins steve set 0
/coins steve get
*/
public CoinsCommand() {
public CoinsCommand(BukkitKenCommandApi commandManager) {
playerArg = Commands.argument0("player", PlayerArgumentType.offlinePlayer(), CommandContext::getSenderPlayer);
amountArg = Commands.argument0("amount", NumberArgumentType.integer(0, Integer.MAX_VALUE));
@ -45,10 +56,6 @@ public class CoinsCommand {
}
}
public RootLiteral create() {
return rootCommand;
}
private void getCoins(CommandContext ctx) {
final var player = ctx.getArg(playerArg);

View file

@ -1,7 +1,7 @@
package de.kentoj.scrow.bukkit.economy;
import com.google.common.base.Preconditions;
import de.kentoj.scrow.bukkit.services.EconomyService;
import de.kentoj.scrow.bukkit.EconomyService;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;

View file

@ -6,9 +6,8 @@ import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.model.Updates;
import com.mongodb.reactivestreams.client.MongoCollection;
import com.mongodb.reactivestreams.client.MongoDatabase;
import de.kentoj.scrow.bukkit.services.EconomyService;
import de.kentoj.scrow.bukkit.EconomyService;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;

View file

@ -1,12 +1,10 @@
package de.kentoj.scrow.bukkit.friends.command;
import de.kentoj.scrow.bukkit.services.command.Commands;
import de.kentoj.scrow.bukkit.services.command.literal.RootLiteral;
import de.kentoj.scrow.bukkit.command.Commands;
import de.kentoj.scrow.bukkit.command.literal.RootLiteral;
public class FriendCommand {
private final RootLiteral rootLiteral;
public FriendCommand() {
rootLiteral = Commands.root("friend");
rootLiteral.addAliases("f", "friends");

View file

@ -1,9 +1,9 @@
package de.kentoj.scrow.bukkit.friends.command;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.services.command.Commands;
import de.kentoj.scrow.bukkit.services.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.services.command.literal.Literal;
import de.kentoj.scrow.bukkit.command.Commands;
import de.kentoj.scrow.bukkit.command.execution.CommandContext;
import de.kentoj.scrow.bukkit.command.literal.Literal;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import reactor.core.scheduler.Schedulers;

View file

@ -1,7 +1,7 @@
package de.kentoj.scrow.bukkit.friends.friendship;
import com.google.common.base.Preconditions;
import de.kentoj.scrow.bukkit.services.friends.Friendship;
import de.kentoj.scrow.bukkit.friends.Friendship;
import de.kentoj.scrow.bukkit.util.pair.Tuple2;
import lombok.Value;
import org.bson.codecs.pojo.annotations.BsonCreator;

View file

@ -1,6 +1,6 @@
package de.kentoj.scrow.bukkit.friends.friendship;
import de.kentoj.scrow.bukkit.services.friends.Friendship;
import de.kentoj.scrow.bukkit.friends.Friendship;
import de.kentoj.scrow.bukkit.util.pair.Tuple2;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Flux;

View file

@ -7,7 +7,7 @@ import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.model.Indexes;
import com.mongodb.reactivestreams.client.MongoCollection;
import com.mongodb.reactivestreams.client.MongoDatabase;
import de.kentoj.scrow.bukkit.services.friends.Friendship;
import de.kentoj.scrow.bukkit.friends.Friendship;
import de.kentoj.scrow.bukkit.util.pair.Tuple2;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Flux;

View file

@ -1,7 +1,7 @@
package de.kentoj.scrow.bukkit.friends.request;
import com.google.common.base.Preconditions;
import de.kentoj.scrow.bukkit.services.friends.FriendRequest;
import de.kentoj.scrow.bukkit.friends.FriendRequest;
import lombok.Value;
import org.bson.codecs.pojo.annotations.BsonCreator;
import org.bson.codecs.pojo.annotations.BsonProperty;

View file

@ -1,6 +1,6 @@
package de.kentoj.scrow.bukkit.friends.request;
import de.kentoj.scrow.bukkit.services.friends.FriendRequest;
import de.kentoj.scrow.bukkit.friends.FriendRequest;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

View file

@ -7,7 +7,7 @@ import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.model.Indexes;
import com.mongodb.reactivestreams.client.MongoCollection;
import com.mongodb.reactivestreams.client.MongoDatabase;
import de.kentoj.scrow.bukkit.services.friends.FriendRequest;
import de.kentoj.scrow.bukkit.friends.FriendRequest;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

View file

@ -1,5 +1,5 @@
name: "CoreBukkit"
version: "1.0"
main: "de.kentoj.scrow.bukkit.CoreImplPlugin"
api-version: "1.1"
api-version: "1.21"
author: "Kento2 <kento@placeq.com>"