Skip to content
This repository was archived by the owner on Feb 3, 2024. It is now read-only.

Commit 8bc0a87

Browse files
committed
Add command support to fabric, other misc improvement
1 parent 73873cc commit 8bc0a87

File tree

26 files changed

+868
-34
lines changed

26 files changed

+868
-34
lines changed

Diff for: api/src/main/java/ca/stellardrift/permissionsex/context/ContextValue.java

+32-1
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,27 @@
1616
*/
1717
package ca.stellardrift.permissionsex.context;
1818

19+
import net.kyori.adventure.text.Component;
20+
import net.kyori.adventure.text.ComponentLike;
21+
import net.kyori.adventure.text.format.NamedTextColor;
22+
import net.kyori.adventure.text.format.TextColor;
23+
import net.kyori.adventure.text.format.TextDecoration;
24+
import org.checkerframework.checker.nullness.qual.NonNull;
1925
import org.checkerframework.checker.nullness.qual.Nullable;
2026

27+
import static net.kyori.adventure.text.Component.text;
28+
import static net.kyori.adventure.text.format.Style.style;
29+
2130
/**
2231
* A (key, value) pair for one specific context entry.
2332
*
2433
* <p>This value holds both raw and parsed context values.</p>
2534
*
2635
* @param <V> value type
2736
*/
28-
public final class ContextValue<V> {
37+
public final class ContextValue<V> implements ComponentLike {
38+
private static final Component JOINER = text("=");
39+
2940
private final String key;
3041
private final String rawValue;
3142
private @Nullable ContextDefinition<V> definition;
@@ -139,4 +150,24 @@ public int hashCode() {
139150
public String toString() {
140151
return this.key + ":" + this.parsedValue + " (raw: " + this.rawValue + ")";
141152
}
153+
154+
@Override
155+
public @NonNull Component asComponent() {
156+
if (this.parsedValue != null) {
157+
return text()
158+
.content(this.key)
159+
.append(JOINER)
160+
.append(text(this.parsedValue.toString()))
161+
.hoverEvent(text("(raw: " + this.rawValue + ")"))
162+
.build();
163+
} else {
164+
return text()
165+
.content(this.key)
166+
.append(JOINER)
167+
.append(text(this.rawValue))
168+
.hoverEvent(text("(unresolved)", style(TextDecoration.BOLD, NamedTextColor.RED)))
169+
.build();
170+
}
171+
}
172+
142173
}

Diff for: core/src/main/java/ca/stellardrift/permissionsex/impl/subject/CalculatedSubjectImpl.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -158,18 +158,18 @@ private <T> void handleAccumulateSingle(ContextDefinition<T> def, Set<ContextVal
158158
@Override
159159
public int permission(Set<ContextValue<?>> contexts, String permission) {
160160
int ret = permissions(contexts).get(Objects.requireNonNull(permission, "permission"));
161+
if (ret == 0) {
162+
if (this.containingType().type().undefinedPermissionValue(this.identifier.identifier())) {
163+
ret = 1;
164+
}
165+
}
161166
getManager().getNotifier().onPermissionCheck(identifier(), contexts, permission, ret);
162167
return ret;
163168
}
164169

165170
@Override
166171
public boolean hasPermission(Set<ContextValue<?>> contexts, String permission) {
167-
final int perm = permission(contexts, permission);
168-
if (perm == 0) {
169-
return containingType().type().undefinedPermissionValue(this.identifier.identifier());
170-
} else {
171-
return perm > 0;
172-
}
172+
return this.permission(contexts, permission) > 0;
173173
}
174174

175175
@Override

Diff for: impl-blocks/minecraft/src/main/java/ca/stellardrift/permissionsex/minecraft/BrigadierRegistration.java

+10-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package ca.stellardrift.permissionsex.minecraft;
1818

19+
import ca.stellardrift.permissionsex.minecraft.command.argument.OptionValueParser;
1920
import ca.stellardrift.permissionsex.minecraft.command.argument.PatternParser;
2021
import cloud.commandframework.CommandManager;
2122
import cloud.commandframework.brigadier.BrigadierManagerHolder;
@@ -31,23 +32,29 @@ private BrigadierRegistration() {
3132
}
3233

3334
@SuppressWarnings("unchecked")
34-
static void registerArgumentTypes(final CommandManager<?> manager) {
35+
static <C> void registerArgumentTypes(final CommandManager<C> manager) {
3536
if (!(manager instanceof BrigadierManagerHolder)) {
3637
return;
3738
}
3839

39-
final @Nullable CloudBrigadierManager<?, ?> brig = ((BrigadierManagerHolder<?>) manager).brigadierManager();
40+
final @Nullable CloudBrigadierManager<C, ?> brig = ((BrigadierManagerHolder<C>) manager).brigadierManager();
4041
if (brig == null) {
4142
return;
4243
}
4344

44-
brig.registerMapping(TypeToken.get(PatternParser.class), true, parser -> {
45+
brig.registerMapping(new TypeToken<PatternParser<C>>() {}, true, parser -> {
4546
if (parser.greedy()) {
4647
return StringArgumentType.greedyString();
4748
} else {
4849
return StringArgumentType.string();
4950
}
5051
});
52+
53+
brig.registerMapping(
54+
new TypeToken<OptionValueParser<C>>() {},
55+
false,
56+
parser -> StringArgumentType.greedyString()
57+
);
5158
}
5259

5360
}

Diff for: impl-blocks/minecraft/src/main/java/ca/stellardrift/permissionsex/minecraft/MinecraftPermissionsEx.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import ca.stellardrift.permissionsex.minecraft.command.CommandException;
2727
import ca.stellardrift.permissionsex.minecraft.command.CommandRegistrationContext;
2828
import ca.stellardrift.permissionsex.minecraft.command.Commander;
29+
import ca.stellardrift.permissionsex.minecraft.command.Formats;
2930
import ca.stellardrift.permissionsex.minecraft.command.MessageFormatter;
3031
import ca.stellardrift.permissionsex.minecraft.command.PEXCommandPreprocessor;
3132
import ca.stellardrift.permissionsex.minecraft.command.definition.PermissionsExCommand;
@@ -286,8 +287,8 @@ private void configureCommandManager() {
286287
sender.error(Messages.COMMAND_ERROR_UNKNOWN.tr(), cause);
287288
this.engine.logger().error(Messages.COMMAND_ERROR_UNKNOWN_CONSOLE.tr(
288289
/* sender */ sender.name(),
289-
/* command */ "not yet implemented", // coming cloud 1.4.0
290-
/* message */ ComponentMessageThrowable.getOrConvertMessage(cause)
290+
/* command */ err.getCommandContext().getRawInputJoined(),
291+
/* message */ Formats.message(cause)
291292
));
292293
}
293294
});

Diff for: impl-blocks/minecraft/src/main/java/ca/stellardrift/permissionsex/minecraft/command/Formats.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
* Message creators for use in command output.
3838
*/
3939
public final class Formats {
40+
public static final Component COMMA = text(",");
4041
private static final Component BOOL_TRUE = Messages.FORMATTER_BOOLEAN_TRUE.bTr()
4142
.color(NamedTextColor.GREEN)
4243
.build();
@@ -102,7 +103,7 @@ public static Component contexts(final Set<ContextValue<?>> contexts) {
102103
if (contexts.isEmpty()) {
103104
return Messages.COMMON_ARGS_CONTEXT_GLOBAL.tr();
104105
} else {
105-
return text(contexts.toString());
106+
return Component.join(COMMA, contexts);
106107
}
107108
}
108109

Diff for: impl-blocks/minecraft/src/main/java/ca/stellardrift/permissionsex/minecraft/command/argument/ContextValueParser.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ public final class ContextValueParser implements ArgumentParser<Commander, Conte
6565
return ArgumentParseResult.failure(new CommandException(Messages.CONTEXT_ERROR_TYPE.tr(contexts[0])));
6666
}
6767

68-
return toContextValue(definition, contexts[1]);
68+
final ArgumentParseResult<ContextValue<?>> result = toContextValue(definition, contexts[1]);
69+
if (result.getParsedValue().isPresent()) {
70+
queue.remove();
71+
}
72+
return result;
6973
}
7074

7175
private <V> ArgumentParseResult<ContextValue<?>> toContextValue(final ContextDefinition<V> definition, final String input) {
@@ -84,7 +88,7 @@ private <V> ArgumentParseResult<ContextValue<?>> toContextValue(final ContextDef
8488
final String[] split = CONTEXT_SPLIT.split(input, 2);
8589
if (split.length < 2) { // before =
8690
return manager.engine().registeredContextTypes().stream()
87-
.map(ContextDefinition::name)
91+
.map(def -> def.name() + "=")
8892
.collect(Collectors.toList());
8993
} else { // <fully written type>=<partial value
9094
final @Nullable ContextDefinition<?> definition = manager.engine().contextDefinition(split[0]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* PermissionsEx
3+
* Copyright (C) zml and PermissionsEx contributors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package ca.stellardrift.permissionsex.minecraft.command.argument;
18+
19+
import ca.stellardrift.permissionsex.minecraft.command.CommandException;
20+
import cloud.commandframework.arguments.parser.ArgumentParseResult;
21+
import cloud.commandframework.arguments.parser.ArgumentParser;
22+
import cloud.commandframework.context.CommandContext;
23+
import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
24+
import org.checkerframework.checker.nullness.qual.NonNull;
25+
import org.checkerframework.checker.nullness.qual.Nullable;
26+
27+
import java.util.Queue;
28+
29+
public final class OptionValueParser<C> implements ArgumentParser<C, String> {
30+
private static final char ESCAPE = '\\';
31+
private static final String FLAG_STARTER = "-";
32+
33+
OptionValueParser() {
34+
}
35+
36+
@Override
37+
public @NonNull ArgumentParseResult<@NonNull String> parse(
38+
@NonNull final CommandContext<@NonNull C> commandContext,
39+
@NonNull final Queue<@NonNull String> inputQueue
40+
) {
41+
final @Nullable String input = inputQueue.peek();
42+
if (input == null || input.startsWith(FLAG_STARTER)) {
43+
return ArgumentParseResult.failure(new NoInputProvidedException(
44+
PermissionValueParser.class,
45+
commandContext
46+
));
47+
}
48+
49+
final char startChar = input.charAt(0);
50+
51+
// If quoted string: read until a word ending with a quote
52+
if (startChar == '\'' || startChar == '\"') {
53+
final StringBuilder result = new StringBuilder();
54+
result.append(inputQueue.remove(), 1, input.length());
55+
@Nullable String next;
56+
while ((next = inputQueue.peek()) != null) {
57+
result.append(" ");
58+
if (next.length() > 0 && next.charAt(next.length() - 1) == startChar) {
59+
// We've found the end of a quoted string, maybe
60+
// if escaped, append without escape then continue
61+
if (next.charAt(next.length() - 1) == ESCAPE) {
62+
result.append(inputQueue.remove(), 0, next.length() - 2)
63+
.append(startChar);
64+
continue;
65+
} else {
66+
result.append(inputQueue.remove(), 0, next.length() - 1);
67+
// then return our full quoted string
68+
return ArgumentParseResult.success(result.toString());
69+
}
70+
}
71+
result.append(inputQueue.remove());
72+
}
73+
74+
// If we made it to the end without finding an end quote, throw an error
75+
return ArgumentParseResult.failure(new CommandException(Messages.OPTION_VALUE_ERROR_QUOTE_UNTERMINATED.tr()));
76+
} else { // otherwise, read until end of line, or a word starting with '-'
77+
final StringBuilder result = new StringBuilder();
78+
result.append(inputQueue.remove());
79+
@Nullable String next;
80+
while ((next = inputQueue.peek()) != null) {
81+
if (next.startsWith(FLAG_STARTER)) {
82+
break;
83+
}
84+
result.append(" ").append(inputQueue.remove());
85+
}
86+
87+
return ArgumentParseResult.success(result.toString());
88+
}
89+
}
90+
91+
@Override
92+
public boolean isContextFree() {
93+
return true;
94+
}
95+
96+
}

Diff for: impl-blocks/minecraft/src/main/java/ca/stellardrift/permissionsex/minecraft/command/argument/Parsers.java

+15
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public final class Parsers {
3232
private static final SubjectTypeParser<Object> SUBJECT_TYPE = new SubjectTypeParser<>();
3333
private static final PatternParser<Object> GREEDY_PATTERN = new PatternParser<>(true);
3434
private static final PatternParser<Object> NON_GREEDY_PATTERN = new PatternParser<>(false);
35+
private static final OptionValueParser<Object> OPTION_VALUE = new OptionValueParser<>();
3536

3637
public static ContextValueParser contextValue() {
3738
return CONTEXT_VALUE;
@@ -83,6 +84,20 @@ public static <C> PatternParser<C> greedyPattern() {
8384
return (PatternParser<C>) GREEDY_PATTERN;
8485
}
8586

87+
88+
/**
89+
* Get a parser for an option value.
90+
*
91+
* <p>This will read a greedy string up until a flag start character is found, or the end of a quoted block is found</p>
92+
*
93+
* @param <C> the sender type
94+
* @return a parser
95+
*/
96+
@SuppressWarnings("unchecked")
97+
public static <C> OptionValueParser<C> optionValue() {
98+
return (OptionValueParser<C>) OPTION_VALUE;
99+
}
100+
86101
private Parsers() {
87102

88103
}

Diff for: impl-blocks/minecraft/src/main/java/ca/stellardrift/permissionsex/minecraft/command/argument/PermissionValueParser.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import java.util.Map;
3131
import java.util.Queue;
3232

33-
public class PermissionValueParser<C> implements ArgumentParser<C, Integer> {
33+
public final class PermissionValueParser<C> implements ArgumentParser<C, Integer> {
3434
private static final Map<String, Integer> CONSTANTS = PCollections.map("true", 1)
3535
.plus("yes", 1)
3636
.plus("false", -1)

Diff for: impl-blocks/minecraft/src/main/java/ca/stellardrift/permissionsex/minecraft/command/definition/InfoSubcommand.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ void printInfo() {
8787
echo(hl(Messages.INFO_ASSOCIATED_OBJECT.bTr()).append(text(associatedObject.toString())));
8888
}
8989
}
90-
echo(hlKeyValue(Messages.INFO_ACTIVE_CONTEXTS.bTr(), text(subject.activeContexts().toString())));
91-
echo(hlKeyValue(Messages.INFO_ACTIVE_USED_CONTEXTS.bTr(), text(subject.usedContextValues().join().toString())));
90+
echo(hlKeyValue(Messages.INFO_ACTIVE_CONTEXTS.bTr(), Component.join(Formats.COMMA, subject.activeContexts())));
91+
echo(hlKeyValue(Messages.INFO_ACTIVE_USED_CONTEXTS.bTr(), Component.join(Formats.COMMA, subject.usedContextValues().join())));
9292

9393
printPermissions(Messages.INFO_HEADER_PERMISSIONS, persistentData);
9494
printPermissions(Messages.INFO_HEADER_PERMISSIONS_TRANSIENT, transientData);

Diff for: impl-blocks/minecraft/src/main/java/ca/stellardrift/permissionsex/minecraft/command/definition/OptionSubcommand.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import ca.stellardrift.permissionsex.minecraft.command.Elements;
2323
import ca.stellardrift.permissionsex.minecraft.command.Formats;
2424
import ca.stellardrift.permissionsex.minecraft.command.Permission;
25+
import ca.stellardrift.permissionsex.minecraft.command.argument.Parsers;
2526
import ca.stellardrift.permissionsex.subject.SubjectRef;
2627
import cloud.commandframework.Command;
2728
import cloud.commandframework.arguments.CommandArgument;
@@ -43,8 +44,10 @@ static Command.Builder<Commander> register(final Command.Builder<Commander> buil
4344
final CommandArgument<Commander, String> optionArg = StringArgument.<Commander>newBuilder("option").single()
4445
.withSuggestionsProvider(engineCompletions((engine, input) -> new ArrayList<>(((PermissionsEx<?>) engine).getRecordingNotifier().getKnownOptions())))
4546
.build();
46-
// TODO: Use custom parser that stops at a word starting with `-` (start of flags)
47-
final CommandArgument<Commander, String> optionValueArg = StringArgument.optional("value", StringArgument.StringMode.GREEDY);
47+
final CommandArgument<Commander, String> optionValueArg = CommandArgument.<Commander, String>ofType(String.class, "value")
48+
.withParser(Parsers.optionValue())
49+
.asOptional()
50+
.build();
4851

4952
return builder
5053
.permission(permission)

Diff for: impl-blocks/minecraft/src/main/messages/ca/stellardrift/permissionsex/minecraft/command/argument/messages.properties

+2
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ context.error.format=Contexts must be in the form <key>=<value>
55
context.error.type=Unknown context type {0}
66
context.error.value=Unable to parse value for context {0}
77

8+
option-value.error.quote-unterminated=No matching word ending with a quotation mark was found!
9+
810
pattern.error.syntax=Invalid regular expression syntax for input '{0}' at position {1}: {2}

Diff for: platform/bukkit/src/main/java/ca/stellardrift/permissionsex/bukkit/PEXPermissible.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ private int getPermissionValue(final Set<ContextValue<?>> contexts, final String
9292
* This only takes into account the permission directly being checked having a default set to FALSE or NOT_OP, and not any parents.
9393
* I believe this is incorrect, but the real-world impacts are likely minor -zml
9494
*/
95-
if (ret == 0 && this.plugin.manager().engine().config().getPlatformConfig().fallbackOp()) {
95+
if (ret == 0 && this.plugin.manager().platformConfig().fallbackOp()) {
9696
final Permission perm = this.plugin.permissionList().get(permission);
9797
if (perm == null) {
9898
ret = this.isOp() ? 1 : 0;

Diff for: platform/bukkit/src/main/java/ca/stellardrift/permissionsex/bukkit/PEXVault.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ public boolean playerHas(final @Nullable String world, final OfflinePlayer playe
166166
} else if (value < 0) {
167167
return false;
168168
} else {
169-
return this.pex.manager().engine().config().getPlatformConfig().fallbackOp() && player.isOp();
169+
return this.pex.manager().platformConfig().fallbackOp() && player.isOp();
170170
}
171171
}
172172

Diff for: platform/fabric/build.gradle.kts

+2-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ dependencies {
5757
modImplementation("net.fabricmc.fabric-api:fabric-api:0.29.3+1.16")
5858
modImplementation(include("net.kyori:adventure-platform-fabric:$adventurePlatformVersion") {
5959
exclude("com.google.code.gson")
60+
exclude("ca.stellardrift", "colonel")
6061
})
6162
modImplementation(include("ca.stellardrift:confabricate:2.0.2") {
6263
exclude("com.google.code.gson")
@@ -79,7 +80,7 @@ loom {
7980
}
8081

8182
tasks.withType(AbstractRunTask::class).configureEach {
82-
javaLauncher.set(pexPlatform.developmentRuntime())
83+
// javaLauncher.set(pexPlatform.developmentRuntime())
8384

8485
// Mixin debug options
8586
jvmArgs(

0 commit comments

Comments
 (0)