fabric: Begin work on commands manager for platform
This commit is contained in:
parent
0722bf6ead
commit
eef98da9c9
16 changed files with 737 additions and 8 deletions
|
|
@ -9,12 +9,14 @@ This directory hosts Minecraft specific implementations of cloud. Their features
|
|||
| `cloud-bungee` | BungeeCord | 1.8+ | No |
|
||||
| `cloud-velocity` | Velocity 1.1.0 | 1.7+ | Yes |
|
||||
| `cloud-cloudburst` | CloudBurst 1.0.0 | Bedrock 1.16.20+ | No |
|
||||
| `cloud-fabric` | Minecraft, via Fabric | 1.16+ | Yes |
|
||||
|
||||
|
||||
There is also a `cloud-minecraft-extras` module that contains a few extra minecraft related features
|
||||
|
||||
## cloud-bukkit
|
||||
Bukkit mappings for cloud. If `commodore` is present on the classpath and the server is running at least version 1.13+, Brigadier mappings will be available.
|
||||
Bukkit mappings for cloud. If `commodore` is present on the classpath and the server is running at least version 1.13+, Brigadier
|
||||
mappings will be available.
|
||||
|
||||
### dependency
|
||||
**maven**:
|
||||
|
|
@ -39,7 +41,10 @@ Simply do:
|
|||
final BukkitCommandManager<YourSender> bukkitCommandManager = new BukkitCommandManager<>(
|
||||
yourPlugin, yourExecutionCoordinator, forwardMapper, backwardsMapper);
|
||||
```
|
||||
The `forwardMapper` is a function that maps your chosen sender type to Bukkit's [CommandSender](https://jd.bukkit.org/org/bukkit/command/CommandSender.html), and the `backwardsMapper`does the opposite. In the case that you don't need a custom sender type, you can simply use `CommandSender`as the generic type and pass `Function.identity()` as the forward and backward mappers.
|
||||
The `forwardMapper` is a function that maps your chosen sender type to Bukkit's
|
||||
[CommandSender](https://jd.bukkit.org/org/bukkit/command/CommandSender.html), and the `backwardsMapper` does the opposite. In
|
||||
the case that you don't need a custom sender type, you can simply use `CommandSender`as the generic type
|
||||
and pass `Function.identity()` as the forward and backward mappers.
|
||||
|
||||
### commodore
|
||||
To use commodore, include it as a dependency:
|
||||
|
|
@ -78,7 +83,9 @@ You can check whether or not the running server supports Brigadier, by using `bu
|
|||
|
||||
An example plugin using the `cloud-paper` API can be found [here](https://github.com/Sauilitired/cloud/tree/master/examples/example-bukkit).
|
||||
|
||||
`cloud-paper`works on all Bukkit derivatives and has graceful fallbacks for cases where Paper specific features are missing. It is initialized the same way as the Bukkit manager, except `PaperCommandManager`is used instead. When using Paper 1.15+ Brigadier mappings are available even without commodore present.
|
||||
`cloud-paper`works on all Bukkit derivatives and has graceful fallbacks for cases where Paper specific features are missing. It
|
||||
is initialized the same way as the Bukkit manager, except `PaperCommandManager`is used instead. When using Paper 1.15+ Brigadier
|
||||
mappings are available even without commodore present.
|
||||
|
||||
### dependency
|
||||
**maven**:
|
||||
|
|
@ -98,7 +105,9 @@ dependencies {
|
|||
```
|
||||
|
||||
### asynchronous completions
|
||||
`cloud-paper`supports asynchronous completions when running on Paper. First check if the capability is present, by using `paperCommandManager.queryCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)` and then initialize the asynchronous completion listener by using `paperCommandManager.registerAsynchronousCompletions()`.
|
||||
`cloud-paper`supports asynchronous completions when running on Paper. First check if the capability is present, by using
|
||||
`paperCommandManager.queryCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)` and then initialize the asynchronous
|
||||
completion listener by using `paperCommandManager.registerAsynchronousCompletions()`.
|
||||
|
||||
## cloud-bungee
|
||||
BungeeCord mappings for cloud.
|
||||
|
|
@ -126,7 +135,10 @@ Simply do:
|
|||
final BungeeCommandManager<YourSender> bungeeCommandManager = new BungeeCommandManager<>(
|
||||
yourPlugin, yourExecutionCoordinator, forwardMapper, backwardsMapper);
|
||||
```
|
||||
The `forwardMapper` is a function that maps your chosen sender type to Bungee's [CommandSender](https://ci.md-5.net/job/BungeeCord/ws/api/target/apidocs/net/md_5/bungee/api/CommandSender.html), and the `backwardsMapper`does the opposite. In the case that you don't need a custom sender type, you can simply use `CommandSender`as the generic type and pass `Function.identity()` as the forward and backward mappers.
|
||||
The `forwardMapper` is a function that maps your chosen sender type to Bungee's
|
||||
[CommandSender](https://ci.md-5.net/job/BungeeCord/ws/api/target/apidocs/net/md_5/bungee/api/CommandSender.html), and
|
||||
the `backwardsMapper`does the opposite. In the case that you don't need a custom sender type, you can simply use `CommandSender`as
|
||||
the generic type and pass `Function.identity()` as the forward and backward mappers.
|
||||
|
||||
## cloud-velocity
|
||||
|
||||
|
|
@ -154,7 +166,10 @@ Simply do:
|
|||
final VelocityCommandManager<YourSender> velocityCommandManager = new VelocityCommandManager<>(
|
||||
proxyServer, yourExecutionCoordinator, forwardMapper, backwardsMapper);
|
||||
```
|
||||
The `forwardMapper` is a function that maps your chosen sender type to Velocity's [CommandSource](https://jd.velocitypowered.com/1.1.0/com/velocitypowered/api/command/CommandSource.html), and the `backwardsMapper`does the opposite. In the case that you don't need a custom sender type, you can simply use `CommandSource`as the generic type and pass `Function.identity()` as the forward and backward mappers.
|
||||
The `forwardMapper` is a function that maps your chosen sender type to Velocity's
|
||||
[CommandSource](https://jd.velocitypowered.com/1.1.0/com/velocitypowered/api/command/CommandSource.html), and the
|
||||
`backwardsMapper` does the opposite. In the case that you don't need a custom sender type, you can simply use `CommandSource`as
|
||||
the generic type and pass `Function.identity()` as the forward and backward mappers.
|
||||
|
||||
## cloud-cloudburst
|
||||
|
||||
|
|
@ -182,4 +197,35 @@ Simply do:
|
|||
final CloudburstCommandManager<YourSender> cloudburstCommandManager = new CloudburstCommandManager<>(
|
||||
yourPlugin, yourExecutionCoordinator, forwardMapper, backwardsMapper);
|
||||
```
|
||||
The `forwardMapper` is a function that maps your chosen sender type to Cloudbursts's [CommandSender](https://ci.nukkitx.com/job/NukkitX/job/Nukkit/job/master/javadoc/cn/nukkit/command/CommandSender.html), and the `backwardsMapper`does the opposite. In the case that you don't need a custom sender type, you can simply use `CommandSource`as the generic type and pass `Function.identity()` as the forward and backward mappers.
|
||||
The `forwardMapper` is a function that maps your chosen sender type to Cloudbursts's
|
||||
[CommandSender](https://ci.nukkitx.com/job/NukkitX/job/Nukkit/job/master/javadoc/cn/nukkit/command/CommandSender.html), and the
|
||||
`backwardsMapper` does the opposite. In the case that you don't need a custom sender type, you can simply use `CommandSource` as
|
||||
the generic type and pass `Function.identity()` as the forward and backward mappers.
|
||||
|
||||
|
||||
## cloud-fabric
|
||||
|
||||
cloud mappings for the Fabric mod loader for Minecraft 1.16+
|
||||
|
||||
### dependency
|
||||
|
||||
**gradle**:
|
||||
```groovy
|
||||
dependencies {
|
||||
modImplementation 'cloud.commandframework:cloud-fabric:1.3.0-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
|
||||
Simply do:
|
||||
```java
|
||||
final FabricCommandManager<YourSender> fabricCommandManager = new FabricCommandManager<>(
|
||||
yourExecutionCoordinator, forwarMapper, backwardsMapper);
|
||||
```
|
||||
|
||||
The `forwardMapper` is a function that maps your chosen sender type to Minecraft's
|
||||
[ServerCommandSource](https://maven.fabricmc.net/docs/yarn-1.16.4+build.7/net/minecraft/server/command/ServerCommandSource.html),
|
||||
and the `backwardsMapper` does the opposite.
|
||||
|
||||
In the case that you don't need a custom sender type, you can use the helper method
|
||||
`FabricCommandManager.createNative(yourExecutionCoordinator)` instead, which will create a command manager that works directly
|
||||
with `ServerCommandSource`s.
|
||||
|
|
|
|||
73
cloud-minecraft/cloud-fabric/build.gradle.kts
Normal file
73
cloud-minecraft/cloud-fabric/build.gradle.kts
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
plugins {
|
||||
id("fabric-loom") version "0.5-SNAPSHOT"
|
||||
}
|
||||
|
||||
// Set up a testmod source set
|
||||
val testmod by sourceSets.creating {
|
||||
val main = sourceSets.main.get()
|
||||
compileClasspath += main.compileClasspath
|
||||
runtimeClasspath += main.runtimeClasspath
|
||||
dependencies.add(implementationConfigurationName, main.output)
|
||||
}
|
||||
|
||||
val testmodJar by tasks.creating(Jar::class) {
|
||||
archiveClassifier.set("testmod-dev")
|
||||
group = LifecycleBasePlugin.BUILD_GROUP
|
||||
from(testmod.output)
|
||||
}
|
||||
|
||||
loom.unmappedModCollection.from(testmodJar)
|
||||
|
||||
tasks.withType(ProcessResources::class).configureEach {
|
||||
inputs.property("version", project.version)
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand("version" to project.version)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(Javadoc::class).configureEach {
|
||||
(options as? StandardJavadocDocletOptions)?.apply {
|
||||
links("https://maven.fabricmc.net/docs/yarn-${Versions.fabricMc}+build.${Versions.fabricYarn}/")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft("com.mojang:minecraft:${Versions.fabricMc}")
|
||||
mappings("net.fabricmc:yarn:${Versions.fabricMc}+build.${Versions.fabricYarn}:v2")
|
||||
modImplementation("net.fabricmc:fabric-loader:${Versions.fabricLoader}")
|
||||
modImplementation(fabricApi.module("fabric-command-api-v1", Versions.fabricApi))
|
||||
|
||||
api(include(project(":cloud-core"))!!)
|
||||
implementation(include(project(":cloud-brigadier"))!!)
|
||||
|
||||
include(project(":cloud-services"))
|
||||
include("io.leangen.geantyref:geantyref:${Versions.geantyref}")
|
||||
}
|
||||
|
||||
indra {
|
||||
includeJavaSoftwareComponentInPublications.set(false)
|
||||
configurePublications {
|
||||
// add all the jars that should be included when publishing to maven
|
||||
artifact(tasks.remapJar) {
|
||||
builtBy(tasks.remapJar)
|
||||
}
|
||||
artifact(tasks.sourcesJar) {
|
||||
builtBy(tasks.remapSourcesJar)
|
||||
}
|
||||
|
||||
// Loom is broken with project dependencies in the same build (because it resolves dependencies during configuration)
|
||||
// Please look away
|
||||
pom {
|
||||
withXml {
|
||||
val dependencies = asNode().appendNode("dependencies")
|
||||
sequenceOf("brigadier", "core").forEach {
|
||||
val depNode = dependencies.appendNode("dependency")
|
||||
depNode.appendNode("groupId", project.group)
|
||||
depNode.appendNode("artifactId", "cloud-$it")
|
||||
depNode.appendNode("version", project.version)
|
||||
depNode.appendNode("scope", "compile")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexander Söderberg & Contributors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
package cloud.commandframework.fabric;
|
||||
|
||||
import cloud.commandframework.CommandManager;
|
||||
import cloud.commandframework.CommandTree;
|
||||
import cloud.commandframework.brigadier.BrigadierManagerHolder;
|
||||
import cloud.commandframework.brigadier.CloudBrigadierManager;
|
||||
import cloud.commandframework.context.CommandContext;
|
||||
import cloud.commandframework.execution.AsynchronousCommandExecutionCoordinator;
|
||||
import cloud.commandframework.execution.CommandExecutionCoordinator;
|
||||
import cloud.commandframework.meta.CommandMeta;
|
||||
import cloud.commandframework.meta.SimpleCommandMeta;
|
||||
import net.minecraft.server.command.CommandOutput;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.util.math.Vec2f;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class FabricCommandManager<C> extends CommandManager<C> implements BrigadierManagerHolder<C> {
|
||||
private final Function<ServerCommandSource, C> commandSourceMapper;
|
||||
private final Function<C, ServerCommandSource> backwardsCommandSourceMapper;
|
||||
private final CloudBrigadierManager<C, ServerCommandSource> brigadierManager;
|
||||
|
||||
/**
|
||||
* Create a command manager using native source types.
|
||||
*
|
||||
* @param execCoordinator Execution coordinator instance.
|
||||
* @return a new command manager
|
||||
* @see #FabricCommandManager(Function, Function, Function) for a more thorough explanation
|
||||
*/
|
||||
public static FabricCommandManager<ServerCommandSource> createNative(
|
||||
final Function<CommandTree<ServerCommandSource>, CommandExecutionCoordinator<ServerCommandSource>> execCoordinator
|
||||
) {
|
||||
return new FabricCommandManager<>(execCoordinator, Function.identity(), Function.identity());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new command manager instance.
|
||||
*
|
||||
* @param commandExecutionCoordinator Execution coordinator instance. The coordinator is in charge of executing incoming
|
||||
* commands. Some considerations must be made when picking a suitable execution coordinator
|
||||
* for your platform. For example, an entirely asynchronous coordinator is not suitable
|
||||
* when the parsers used in that particular platform are not thread safe. If you have
|
||||
* commands that perform blocking operations, however, it might not be a good idea to
|
||||
* use a synchronous execution coordinator. In most cases you will want to pick between
|
||||
* {@link CommandExecutionCoordinator#simpleCoordinator()} and
|
||||
* {@link AsynchronousCommandExecutionCoordinator}
|
||||
* @param commandSourceMapper Function that maps {@link ServerCommandSource} to the command sender type
|
||||
* @param backwardsCommandSourceMapper Function that maps the command sender type to {@link ServerCommandSource}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected FabricCommandManager(
|
||||
final @NonNull Function<@NonNull CommandTree<C>, @NonNull CommandExecutionCoordinator<C>> commandExecutionCoordinator,
|
||||
final Function<ServerCommandSource, C> commandSourceMapper,
|
||||
final Function<C, ServerCommandSource> backwardsCommandSourceMapper
|
||||
) {
|
||||
super(commandExecutionCoordinator, new FabricCommandRegistrationHandler<>());
|
||||
this.commandSourceMapper = commandSourceMapper;
|
||||
this.backwardsCommandSourceMapper = backwardsCommandSourceMapper;
|
||||
|
||||
// We're always brigadier
|
||||
this.brigadierManager = new CloudBrigadierManager<>(this, () -> new CommandContext<>(
|
||||
// This looks ugly, but it's what the server does when loading datapack functions in 1.16+
|
||||
// See net.minecraft.server.function.FunctionLoader.reload for reference
|
||||
this.commandSourceMapper.apply(new ServerCommandSource(
|
||||
CommandOutput.DUMMY,
|
||||
Vec3d.ZERO,
|
||||
Vec2f.ZERO,
|
||||
null,
|
||||
4,
|
||||
"",
|
||||
LiteralText.EMPTY,
|
||||
null,
|
||||
null
|
||||
)),
|
||||
this.getCaptionRegistry()
|
||||
));
|
||||
|
||||
((FabricCommandRegistrationHandler<C>) this.getCommandRegistrationHandler()).initialize(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a sender has a certain permission.
|
||||
*
|
||||
* <p>The current implementation checks op level, pending a full Fabric permissions api.</p>
|
||||
*
|
||||
* @param sender Command sender
|
||||
* @param permission Permission node
|
||||
* @return whether the sender has the specified permission
|
||||
*/
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull final C sender, @NonNull final String permission) {
|
||||
final ServerCommandSource source = this.backwardsCommandSourceMapper.apply(sender);
|
||||
return source.hasPermissionLevel(source.getMinecraftServer().getOpPermissionLevel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NonNull CommandMeta createDefaultCommandMeta() {
|
||||
return SimpleCommandMeta.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mapper from a game {@link ServerCommandSource} to the manager's {@code C} type.
|
||||
*
|
||||
* @return Command source mapper
|
||||
*/
|
||||
public final @NonNull Function<@NonNull ServerCommandSource, @NonNull C> getCommandSourceMapper() {
|
||||
return this.commandSourceMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mapper from the manager's {@code C} type to a game {@link ServerCommandSource}.
|
||||
*
|
||||
* @return Command source mapper
|
||||
*/
|
||||
public final @NonNull Function<@NonNull C, @NonNull ServerCommandSource> getBackwardsCommandSourceMapper() {
|
||||
return this.backwardsCommandSourceMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NonNull CloudBrigadierManager<C, ServerCommandSource> brigadierManager() {
|
||||
return this.brigadierManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexander Söderberg & Contributors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
package cloud.commandframework.fabric;
|
||||
|
||||
import cloud.commandframework.Command;
|
||||
import cloud.commandframework.arguments.StaticArgument;
|
||||
import cloud.commandframework.internal.CommandRegistrationHandler;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
import com.mojang.brigadier.tree.RootCommandNode;
|
||||
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* A registration handler for Fabric API.
|
||||
*
|
||||
* <p>If the command registration callback has already been called, this will attempt
|
||||
* to register with the active server's command dispatcher.</p>
|
||||
*
|
||||
* @param <C> command sender type
|
||||
*/
|
||||
public final class FabricCommandRegistrationHandler<C> implements CommandRegistrationHandler {
|
||||
private @MonotonicNonNull FabricCommandManager<C> commandManager;
|
||||
private final Set<Command<C>> registeredCommands = ConcurrentHashMap.newKeySet();
|
||||
private boolean commandRegistrationCalled;
|
||||
|
||||
void initialize(final FabricCommandManager<C> manager) {
|
||||
this.commandManager = manager;
|
||||
CommandRegistrationCallback.EVENT.register(this::registerAllCommands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean registerCommand(@NonNull final Command<?> command) {
|
||||
if (this.commandRegistrationCalled) {
|
||||
throw new IllegalStateException("too late!");
|
||||
}
|
||||
return this.registeredCommands.add((Command<C>) command);
|
||||
}
|
||||
|
||||
private void registerAllCommands(final CommandDispatcher<ServerCommandSource> dispatcher, final boolean isDedicated) {
|
||||
this.commandRegistrationCalled = true;
|
||||
for (final Command<C> command : this.registeredCommands) {
|
||||
registerCommand(dispatcher.getRoot(), command);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerCommand(final RootCommandNode<ServerCommandSource> dispatcher, final Command<C> command) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final StaticArgument<C> first = ((StaticArgument<C>) command.getArguments().get(0));
|
||||
final CommandNode<ServerCommandSource> baseNode = this.commandManager.brigadierManager().createLiteralCommandNode(
|
||||
first.getName(),
|
||||
command,
|
||||
(src, perm) -> this.commandManager.hasPermission(this.commandManager.getCommandSourceMapper().apply(src), perm),
|
||||
true,
|
||||
new FabricExecutor<>(this.commandManager));
|
||||
|
||||
dispatcher.addChild(baseNode);
|
||||
|
||||
for (final String alias : first.getAlternativeAliases()) {
|
||||
dispatcher.addChild(CommandManager.literal(alias).redirect(baseNode).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexander Söderberg & Contributors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
package cloud.commandframework.fabric;
|
||||
|
||||
import cloud.commandframework.exceptions.ArgumentParseException;
|
||||
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
||||
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
||||
import cloud.commandframework.exceptions.NoPermissionException;
|
||||
import cloud.commandframework.exceptions.NoSuchCommandException;
|
||||
import cloud.commandframework.execution.CommandResult;
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.text.ClickEvent;
|
||||
import net.minecraft.text.HoverEvent;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
final class FabricExecutor<C> implements Command<ServerCommandSource> {
|
||||
private static final Text NEWLINE = new LiteralText("\n");
|
||||
private static final String MESSAGE_INTERNAL_ERROR = "An internal error occurred while attempting to perform this command.";
|
||||
private static final String MESSAGE_NO_PERMS =
|
||||
"I'm sorry, but you do not have permission to perform this command. "
|
||||
+ "Please contact the server administrators if you believe that this is in error.";
|
||||
private static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command. Type \"/help\" for help.";
|
||||
|
||||
private final FabricCommandManager<C> manager;
|
||||
|
||||
FabricExecutor(final @NonNull FabricCommandManager<C> manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int run(final @NonNull CommandContext<ServerCommandSource> ctx) {
|
||||
final ServerCommandSource source = ctx.getSource();
|
||||
final String input = ctx.getInput().substring(1);
|
||||
final C sender = this.manager.getCommandSourceMapper().apply(source);
|
||||
this.manager.executeCommand(sender, input).whenComplete(this.getResultConsumer(source, sender));
|
||||
return com.mojang.brigadier.Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private @NonNull BiConsumer<@NonNull CommandResult<C>, ? super Throwable> getResultConsumer(
|
||||
final @NonNull ServerCommandSource source,
|
||||
final @NonNull C sender
|
||||
) {
|
||||
return (result, throwable) -> {
|
||||
if (throwable != null) {
|
||||
if (throwable instanceof CompletionException) {
|
||||
throwable = throwable.getCause();
|
||||
}
|
||||
final Throwable finalThrowable = throwable;
|
||||
if (throwable instanceof InvalidSyntaxException) {
|
||||
this.manager.handleException(
|
||||
sender,
|
||||
InvalidSyntaxException.class,
|
||||
(InvalidSyntaxException) throwable,
|
||||
(c, e) ->
|
||||
source.sendError(
|
||||
new LiteralText("Invalid Command Syntax. Correct command syntax is: ")
|
||||
.append(new LiteralText(e.getCorrectSyntax())
|
||||
.styled(style -> style.withColor(Formatting.GRAY))))
|
||||
);
|
||||
} else if (throwable instanceof InvalidCommandSenderException) {
|
||||
this.manager.handleException(
|
||||
sender,
|
||||
InvalidCommandSenderException.class,
|
||||
(InvalidCommandSenderException) throwable,
|
||||
(c, e) ->
|
||||
source.sendError(new LiteralText(finalThrowable.getMessage()))
|
||||
);
|
||||
} else if (throwable instanceof NoPermissionException) {
|
||||
this.manager.handleException(
|
||||
sender,
|
||||
NoPermissionException.class,
|
||||
(NoPermissionException) throwable,
|
||||
(c, e) -> source.sendError(new LiteralText(MESSAGE_NO_PERMS))
|
||||
);
|
||||
} else if (throwable instanceof NoSuchCommandException) {
|
||||
this.manager.handleException(
|
||||
sender,
|
||||
NoSuchCommandException.class,
|
||||
(NoSuchCommandException) throwable,
|
||||
(c, e) -> source.sendError(new LiteralText(MESSAGE_UNKNOWN_COMMAND))
|
||||
);
|
||||
} else if (throwable instanceof ArgumentParseException) {
|
||||
this.manager.handleException(
|
||||
sender,
|
||||
ArgumentParseException.class,
|
||||
(ArgumentParseException) throwable,
|
||||
(c, e) -> source.sendError(new LiteralText("Invalid Command Argument: ")
|
||||
.append(new LiteralText(finalThrowable.getCause().getMessage())
|
||||
.styled(style -> style.withColor(Formatting.GRAY))))
|
||||
);
|
||||
} else if (throwable instanceof CommandExecutionException) {
|
||||
this.manager.handleException(
|
||||
sender,
|
||||
CommandExecutionException.class,
|
||||
(CommandExecutionException) throwable,
|
||||
(c, e) -> {
|
||||
source.sendError(decorateHoverStacktrace(
|
||||
new LiteralText(MESSAGE_INTERNAL_ERROR),
|
||||
finalThrowable.getCause(),
|
||||
sender
|
||||
));
|
||||
finalThrowable.getCause().printStackTrace();
|
||||
}
|
||||
);
|
||||
} else {
|
||||
source.sendError(decorateHoverStacktrace(
|
||||
new LiteralText(MESSAGE_INTERNAL_ERROR),
|
||||
throwable,
|
||||
sender
|
||||
));
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private MutableText decorateHoverStacktrace(final MutableText input, final Throwable cause, final C sender) {
|
||||
if (!this.manager.hasPermission(sender, "cloud.hover-stacktrace")) {
|
||||
return input;
|
||||
}
|
||||
|
||||
final StringWriter writer = new StringWriter();
|
||||
cause.printStackTrace(new PrintWriter(writer));
|
||||
final String stackTrace = writer.toString().replace("\t", " ");
|
||||
return input.styled(style -> style
|
||||
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
|
||||
new LiteralText(stackTrace)
|
||||
.append(NEWLINE)
|
||||
.append(new LiteralText(" Click to copy")
|
||||
.styled(s2 -> s2
|
||||
.withColor(Formatting.GRAY)
|
||||
.withItalic(true)))
|
||||
))
|
||||
.withClickEvent(new ClickEvent(
|
||||
ClickEvent.Action.COPY_TO_CLIPBOARD,
|
||||
stackTrace
|
||||
)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexander Söderberg & Contributors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
/**
|
||||
* Fabric API-based implementation of Cloud
|
||||
*/
|
||||
package cloud.commandframework.fabric;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "cloud",
|
||||
"version": "${version}",
|
||||
|
||||
"name": "Cloud",
|
||||
"description": "Command framework and dispatcher for the JVM",
|
||||
"authors": [ "Alexander Söderberg" ],
|
||||
"contact": {
|
||||
"homepage": "https://commandframework.cloud/",
|
||||
"sources": "https://github.com/Incendo/cloud"
|
||||
},
|
||||
"license": "MIT",
|
||||
"icon": "assets/cloud/logo.png",
|
||||
|
||||
"depends": {
|
||||
"fabricloader": ">=0.7.4",
|
||||
"fabric-command-api-v1": "*",
|
||||
"minecraft": ">=1.14"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexander Söderberg & Contributors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
package cloud.commandframework.fabric.testmod;
|
||||
|
||||
import cloud.commandframework.arguments.CommandArgument;
|
||||
import cloud.commandframework.arguments.standard.IntegerArgument;
|
||||
import cloud.commandframework.arguments.standard.StringArgument;
|
||||
import cloud.commandframework.execution.CommandExecutionCoordinator;
|
||||
import cloud.commandframework.fabric.FabricCommandManager;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.TextColor;
|
||||
|
||||
public final class FabricExample implements ModInitializer {
|
||||
private static final CommandArgument<ServerCommandSource, String> NAME = StringArgument.of("name");
|
||||
private static final CommandArgument<ServerCommandSource, Integer> HUGS = IntegerArgument.<ServerCommandSource>newBuilder("hugs")
|
||||
.asOptionalWithDefault("1")
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
// Create a commands manager. We'll use native command source types for this.
|
||||
|
||||
final FabricCommandManager<ServerCommandSource> manager =
|
||||
FabricCommandManager.createNative(CommandExecutionCoordinator.simpleCoordinator());
|
||||
|
||||
manager.command(manager.commandBuilder("cloudtest")
|
||||
.argument(NAME)
|
||||
.argument(HUGS)
|
||||
.handler(ctx -> {
|
||||
ctx.getSender().sendFeedback(new LiteralText("Hello, ")
|
||||
.append(ctx.get(NAME))
|
||||
.append(", hope you're doing well!")
|
||||
.styled(style -> style.withColor(TextColor.fromRgb(0xAA22BB))), false);
|
||||
|
||||
ctx.getSender().sendFeedback(new LiteralText("Cloud would like to give you ")
|
||||
.append(new LiteralText(String.valueOf(ctx.get(HUGS)))
|
||||
.styled(style -> style.withColor(TextColor.fromRgb(0xFAB3DA))))
|
||||
.append(" hug(s) <3")
|
||||
.styled(style -> style.withBold(true)), false);
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexander Söderberg & Contributors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
/**
|
||||
* A test mod for the fabric implementation of Cloud.
|
||||
*/
|
||||
package cloud.commandframework.fabric.testmod;
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "cloud-testmod",
|
||||
"version": "${version}",
|
||||
|
||||
"name": "Cloud Test mod",
|
||||
"description": "Command framework and dispatcher for the JVM",
|
||||
"authors": [ "Alexander Söderberg" ],
|
||||
"contact": {
|
||||
"homepage": "https://commandframework.cloud/",
|
||||
"sources": "https://github.com/Incendo/cloud"
|
||||
},
|
||||
"license": "MIT",
|
||||
"icon": "assets/cloud/logo.png",
|
||||
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"cloud.commandframework.fabric.testmod.FabricExample"
|
||||
]
|
||||
},
|
||||
|
||||
"depends": {
|
||||
"fabricloader": ">=0.7.4",
|
||||
"fabric-command-api-v1": "*",
|
||||
"minecraft": ">=1.14",
|
||||
"cloud": "*"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue