diff --git a/README.md b/README.md
index a0a1c89..7f14766 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@
Versions are available on maven in the format `net.william278.uniform:ARTIFACT:VERSION`. See below for a table of supported platforms.
-Note that Uniform versions omit the `v` prefix. Fabric versions are suffixed with the target Minecraft version (e.g. `1.2+1.21`) and also require Fabric API installed on the server. Sponge versions are suffixed with the target Sponge API version (e.g. `1.2+11`).
+Note that Uniform versions omit the `v` prefix. Fabric versions are suffixed with the target Minecraft version (e.g. `1.2.1+1.21`) and also require Fabric API installed on the server. Sponge versions are suffixed with the target Sponge API version (e.g. `1.2.1+11`).
@@ -89,7 +89,7 @@ Note that Uniform versions omit the `v` prefix. Fabric versions are suffixed wit
-Example: To target Uniform on Bukkit, the artifact is `net.william278.uniform:uniform-bukkit:1.2` (check that this version is up-to-date – make sure you target the latest available!).
+Example: To target Uniform on Bukkit, the artifact is `net.william278.uniform:uniform-bukkit:1.2.1` (check that this version is up-to-date – make sure you target the latest available!).
## Setup
Uniform is available [on Maven](https://repo.william278.net/#/releases/net/william278/uniform/). You can browse the Javadocs [here](https://repo.william278.net/javadoc/releases/net/william278/uniform/latest).
@@ -104,7 +104,7 @@ repositories {
}
```
-Then, add the dependency itself. Replace `VERSION` with the latest release version. (e.g., `1.2`) and `PLATFORM` with the platform you are targeting (e.g., `paper`). If you want to target pre-release "snapshot" versions (not recommended), you should use the `/snapshots` repository instead.
+Then, add the dependency itself. Replace `VERSION` with the latest release version. (e.g., `1.2.1`) and `PLATFORM` with the platform you are targeting (e.g., `paper`). If you want to target pre-release "snapshot" versions (not recommended), you should use the `/snapshots` repository instead.
```groovy
dependencies {
diff --git a/common/src/main/java/net/william278/uniform/BaseCommand.java b/common/src/main/java/net/william278/uniform/BaseCommand.java
index 5ad9026..7c5a83c 100644
--- a/common/src/main/java/net/william278/uniform/BaseCommand.java
+++ b/common/src/main/java/net/william278/uniform/BaseCommand.java
@@ -55,6 +55,7 @@ public abstract class BaseCommand {
this.name = command.getName();
this.aliases = command.getAliases();
this.description = command.getDescription();
+ setExecutionScope(command.getScope());
command.getPermission().ifPresent(this::setPermission);
command.provide(this);
}
@@ -79,8 +80,16 @@ public abstract class BaseCommand {
this.condition = condition;
}
+ public final void addCondition(@NotNull Predicate condition) {
+ if (this.condition == null) {
+ this.condition = condition;
+ } else {
+ this.condition = this.condition.and(condition);
+ }
+ }
+
public void setPermission(@NotNull Permission permission) {
- this.setCondition(this.createPermission(permission));
+ this.addCondition(this.createPermission(permission));
}
public final void setPermission(@NotNull String permission) {
@@ -91,6 +100,13 @@ public abstract class BaseCommand {
this.setPermission(new Permission(permission, permissionDefault));
}
+ public final void setExecutionScope(@NotNull Command.ExecutionScope scope) {
+ final Predicate predicate = scope.toPredicate(this);
+ if (predicate != null) {
+ this.addCondition(predicate);
+ }
+ }
+
public final void setDefaultExecutor(@NotNull CommandExecutor executor) {
this.defaultExecutor = executor;
}
@@ -130,6 +146,12 @@ public abstract class BaseCommand {
this.addSubCommand(new Command.SubCommand(name, aliases, permission, provider).command());
}
+ public final void addSubCommand(@NotNull String name, @NotNull List aliases,
+ @NotNull Permission permission, @NotNull Command.ExecutionScope scope,
+ @NotNull CommandProvider provider) {
+ this.addSubCommand(new Command.SubCommand(name, aliases, permission, scope, provider).command());
+ }
+
public abstract void addSubCommand(@NotNull Command command);
public abstract Uniform getUniform();
diff --git a/common/src/main/java/net/william278/uniform/Command.java b/common/src/main/java/net/william278/uniform/Command.java
index 15b1e6f..81e4243 100644
--- a/common/src/main/java/net/william278/uniform/Command.java
+++ b/common/src/main/java/net/william278/uniform/Command.java
@@ -55,6 +55,7 @@ public abstract class Command implements CommandProvider {
private String description = "";
@Getter(AccessLevel.NONE)
private @Nullable Permission permission = null;
+ private ExecutionScope scope = ExecutionScope.ALL;
public Optional getPermission() {
return Optional.ofNullable(permission);
@@ -71,9 +72,29 @@ public abstract class Command implements CommandProvider {
this.name = node.value();
this.aliases = List.of(node.aliases());
this.description = node.description();
+ this.scope = node.scope();
Permission.annotated(node.permission()).ifPresent(this::setPermission);
}
+ public enum ExecutionScope {
+ IN_GAME,
+ CONSOLE,
+ ALL;
+
+ @Nullable
+ public Predicate toPredicate(@NotNull BaseCommand command) {
+ return this == ALL ? null : user -> this.contains(command.getUser(user));
+ }
+
+ public boolean contains(@NotNull CommandUser user) {
+ return switch (this) {
+ case IN_GAME -> !user.isConsole();
+ case CONSOLE -> user.isConsole();
+ case ALL -> true;
+ };
+ }
+ }
+
static class AnnotatedCommand extends Command {
private final Object annotated;
@@ -102,11 +123,15 @@ public abstract class Command implements CommandProvider {
continue;
}
- // Conditional & unconditional syntax
+ // Determine predicates
final Optional perm = Permission.annotated(syntax.permission()).map(p -> p.toPredicate(cmd));
+ final Optional scope = Optional.ofNullable(syntax.scope().toPredicate(cmd));
+ final Optional combined = scope.map(sp -> perm.map(pp -> sp.and(pp)).orElse(sp));
+
+ // Conditional & unconditional syntax
final CommandExecutor executor = methodToExecutor(method, annotated, cmd);
- if (perm.isPresent()) {
- cmd.addConditionalSyntax(perm.get(), executor, args);
+ if (combined.isPresent()) {
+ cmd.addConditionalSyntax(combined.get(), executor, args);
continue;
}
cmd.addSyntax(executor, args);
@@ -170,22 +195,28 @@ public abstract class Command implements CommandProvider {
}
public record SubCommand(@NotNull String name, @NotNull List aliases, @Nullable Permission permission,
- @NotNull CommandProvider provider) {
- public SubCommand(@NotNull String name, @NotNull List aliases, @NotNull CommandProvider provider) {
- this(name, aliases, null, provider);
+ @NotNull ExecutionScope scope, @NotNull CommandProvider provider) {
+ public SubCommand(@NotNull String name, @NotNull List aliases, @Nullable Permission permission,
+ @NotNull CommandProvider provider) {
+ this(name, aliases, permission, ExecutionScope.ALL, provider);
}
- public SubCommand(@NotNull String name, @NotNull CommandProvider provider) {
- this(name, List.of(), null, provider);
+ public SubCommand(@NotNull String name, @NotNull List aliases, @NotNull CommandProvider provider) {
+ this(name, aliases, null, ExecutionScope.ALL, provider);
}
public SubCommand(@NotNull String name, @Nullable Permission permission, @NotNull CommandProvider provider) {
- this(name, List.of(), permission, provider);
+ this(name, List.of(), permission, ExecutionScope.ALL, provider);
}
+ public SubCommand(@NotNull String name, @NotNull CommandProvider provider) {
+ this(name, List.of(), null, ExecutionScope.ALL, provider);
+ }
+
+
@NotNull
Command command() {
- return new Command(name, aliases, "", permission) {
+ return new Command(name, aliases, "", permission, scope) {
@Override
public void provide(@NotNull BaseCommand> command) {
provider.provide(command);
diff --git a/common/src/main/java/net/william278/uniform/annotations/CommandNode.java b/common/src/main/java/net/william278/uniform/annotations/CommandNode.java
index 33e4516..4d58331 100644
--- a/common/src/main/java/net/william278/uniform/annotations/CommandNode.java
+++ b/common/src/main/java/net/william278/uniform/annotations/CommandNode.java
@@ -21,6 +21,8 @@
package net.william278.uniform.annotations;
+import net.william278.uniform.Command;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -34,5 +36,6 @@ public @interface CommandNode {
String[] aliases() default {};
String description() default "";
PermissionNode permission() default @PermissionNode("");
+ Command.ExecutionScope scope() default Command.ExecutionScope.ALL;
}
\ No newline at end of file
diff --git a/common/src/main/java/net/william278/uniform/annotations/Syntax.java b/common/src/main/java/net/william278/uniform/annotations/Syntax.java
index ed1b92f..100d3d2 100644
--- a/common/src/main/java/net/william278/uniform/annotations/Syntax.java
+++ b/common/src/main/java/net/william278/uniform/annotations/Syntax.java
@@ -21,6 +21,8 @@
package net.william278.uniform.annotations;
+import net.william278.uniform.Command;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -29,5 +31,8 @@ import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Syntax {
+
PermissionNode permission() default @PermissionNode("");
+ Command.ExecutionScope scope() default Command.ExecutionScope.ALL;
+
}
diff --git a/gradle.properties b/gradle.properties
index 21f3d78..90a8339 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -3,6 +3,6 @@ javaVersion=17
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
org.gradle.daemon=true
-library_version=1.2
+library_version=1.2.1
library_archive=uniform
library_description=Cross-platform wrapper for making Brigadier commands, based on BrigadierWrapper by Tofaa2, itself inspired by emortalmcs command system.
\ No newline at end of file