From eef98da9c90afec0885a205387f4ad77d87568ee Mon Sep 17 00:00:00 2001 From: Zach Levis Date: Tue, 24 Nov 2020 21:39:29 -0800 Subject: [PATCH] fabric: Begin work on commands manager for platform --- .gitignore | 4 + README.md | 1 + buildSrc/src/main/kotlin/Versions.kt | 4 + cloud-minecraft/README.md | 60 +++++- cloud-minecraft/cloud-fabric/build.gradle.kts | 73 ++++++++ .../fabric/FabricCommandManager.java | 152 +++++++++++++++ .../FabricCommandRegistrationHandler.java | 92 +++++++++ .../fabric/FabricExecutor.java | 174 ++++++++++++++++++ .../commandframework/fabric/package-info.java | 28 +++ .../src/main/resources/assets/cloud/logo.png | Bin 0 -> 6252 bytes .../src/main/resources/fabric.mod.json | 21 +++ .../fabric/testmod/FabricExample.java | 68 +++++++ .../fabric/testmod/package-info.java | 28 +++ .../src/testmod/resources/fabric.mod.json | 28 +++ gradle.properties | 2 +- settings.gradle.kts | 10 + 16 files changed, 737 insertions(+), 8 deletions(-) create mode 100644 cloud-minecraft/cloud-fabric/build.gradle.kts create mode 100644 cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricCommandManager.java create mode 100644 cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricCommandRegistrationHandler.java create mode 100644 cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricExecutor.java create mode 100644 cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/package-info.java create mode 100644 cloud-minecraft/cloud-fabric/src/main/resources/assets/cloud/logo.png create mode 100644 cloud-minecraft/cloud-fabric/src/main/resources/fabric.mod.json create mode 100644 cloud-minecraft/cloud-fabric/src/testmod/java/cloud/commandframework/fabric/testmod/FabricExample.java create mode 100644 cloud-minecraft/cloud-fabric/src/testmod/java/cloud/commandframework/fabric/testmod/package-info.java create mode 100644 cloud-minecraft/cloud-fabric/src/testmod/resources/fabric.mod.json diff --git a/.gitignore b/.gitignore index 9d64cf5a..740c5580 100644 --- a/.gitignore +++ b/.gitignore @@ -222,3 +222,7 @@ gradle-app.setting **/build/ # End of https://www.toptal.com/developers/gitignore/api/git,java,eclipse,jetbrains+all,gradle + +### Fabric Loom run files ### + +/run/ diff --git a/README.md b/README.md index 5694cb75..b574bafb 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ The code is based on a (W.I.P) paper that can be found [here](https://github.com - **cloud-minecraft/cloud-bungee**: BungeeCord 1.8.8+ implementation of Cloud - **cloud-minecraft/cloud-velocity**: Velocity v1.1.0 implementation of cloud - **cloud-minecraft/cloud-cloudburst**: Cloudburst v1.0.0+ implementation of cloud +- **cloud-minecraft/cloud-fabric**: Fabric implementation of Cloud - **cloud-minecraft/cloud-minecraft-extras**: Opinionated Extra Features for cloud-minecraft - **cloud-discord/cloud-jda**: JDA v4.2.0_209+ implementation of cloud - **cloud-discord/cloud-javacord**: Javacord v3.1.1+ implementation of cloud diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 2dd289a6..ccb02050 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -23,6 +23,10 @@ object Versions { const val spongeApi7 = "7.3.0" const val jetbrainsAnnotations = "20.1.0" const val guava = "21.0-jre" + const val fabricLoader = "0.10.8" + const val fabricMc = "1.16.4" + const val fabricYarn = "7" + const val fabricApi = "0.29.1+1.16" // IRC DEPENDENCIES const val pircbotx = "83a4c22e80" diff --git a/cloud-minecraft/README.md b/cloud-minecraft/README.md index 5ca12894..e42e3d7a 100644 --- a/cloud-minecraft/README.md +++ b/cloud-minecraft/README.md @@ -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 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 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 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 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 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. diff --git a/cloud-minecraft/cloud-fabric/build.gradle.kts b/cloud-minecraft/cloud-fabric/build.gradle.kts new file mode 100644 index 00000000..d394a6a9 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/build.gradle.kts @@ -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") + } + } + } + } +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricCommandManager.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricCommandManager.java new file mode 100644 index 00000000..cf5e5a78 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricCommandManager.java @@ -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 extends CommandManager implements BrigadierManagerHolder { + private final Function commandSourceMapper; + private final Function backwardsCommandSourceMapper; + private final CloudBrigadierManager 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 createNative( + final Function, CommandExecutionCoordinator> 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, @NonNull CommandExecutionCoordinator> commandExecutionCoordinator, + final Function commandSourceMapper, + final Function 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) this.getCommandRegistrationHandler()).initialize(this); + } + + /** + * Check if a sender has a certain permission. + * + *

The current implementation checks op level, pending a full Fabric permissions api.

+ * + * @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 brigadierManager() { + return this.brigadierManager; + } + +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricCommandRegistrationHandler.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricCommandRegistrationHandler.java new file mode 100644 index 00000000..4191775b --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricCommandRegistrationHandler.java @@ -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. + * + *

If the command registration callback has already been called, this will attempt + * to register with the active server's command dispatcher.

+ * + * @param command sender type + */ +public final class FabricCommandRegistrationHandler implements CommandRegistrationHandler { + private @MonotonicNonNull FabricCommandManager commandManager; + private final Set> registeredCommands = ConcurrentHashMap.newKeySet(); + private boolean commandRegistrationCalled; + + void initialize(final FabricCommandManager 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) command); + } + + private void registerAllCommands(final CommandDispatcher dispatcher, final boolean isDedicated) { + this.commandRegistrationCalled = true; + for (final Command command : this.registeredCommands) { + registerCommand(dispatcher.getRoot(), command); + } + } + + private void registerCommand(final RootCommandNode dispatcher, final Command command) { + @SuppressWarnings("unchecked") + final StaticArgument first = ((StaticArgument) command.getArguments().get(0)); + final CommandNode 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()); + } + } +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricExecutor.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricExecutor.java new file mode 100644 index 00000000..e561b8a5 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricExecutor.java @@ -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 implements Command { + 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 manager; + + FabricExecutor(final @NonNull FabricCommandManager manager) { + this.manager = manager; + } + + @Override + public int run(final @NonNull CommandContext 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, ? 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 + ))); + } + +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/package-info.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/package-info.java new file mode 100644 index 00000000..a7cb2418 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/package-info.java @@ -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; diff --git a/cloud-minecraft/cloud-fabric/src/main/resources/assets/cloud/logo.png b/cloud-minecraft/cloud-fabric/src/main/resources/assets/cloud/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..42acc7182449525553c76228e998507a9403a578 GIT binary patch literal 6252 zcmdT}cQjmUyWgZ}kw`>@L=bm%!y?@+w*SfQowfBCXvY+So)V+jgYbw!FGgCtlM604KuM0tB z;Fb)cBnOvvI$2=|I`|HyZ;Uh6P)FFIU12u%Xj>%A+Z6-o5F{n*jj^%2j>NIsA{|j~ z(j1GWl^pCSdua|MQ4Jvtj2zMlrR?K@)br8QxAVDfCuz?iD?=^ijQ|Qg;cUDG+_0Q`Dt_vaM`GR)5aFl_R}TzqGqye|H}MA-G2o6ov^2{yRGkLRgdPY*k!f)~;a$GMNh9xe!NlsD4FSRUnybi)F4r8(fDV*iP1@=sJbvvsd*L;3Ljix_zqA?uqDgaz!$D&0 z1$|$i$={Oxhy`NbJ`J=zFz?d7)Gv~XoSe1?+5zPPXjomPYwRita$>@gVqyYt*iTnL z;1EC-#07*T5JErg+2;oJU~hx7`S1AmvYK5A zNN8vvlu=k5+Jmrv^fT4-L!h4q-Ks&pM0)hEUKp==G z!ZV_UPhRI_gRH}Er*-&wW|D30{74H4t5XkPIA!$SWZ0vrV>{Y? zvoa_v&+wjd(}$Ya&o3sWw8HF3^ZhHuL%uE3gV<_%6=&XzG78=4OeR*^i}~0U)p1Ty z5xob|h6effo2DZux#s8Z!nrLyB@0xaZ*@CI;nZ&BT^u<_6w0r$tD)yJc|W2tqA2hZ zM#V;hkM+1Za$PCBxkN$t)Mehx4ub7PsDQ6QDs~2{p!*OTI!&7kyr)ZQ@_L z(Q1-HO>s1u-7lv}+8S$S%lCY3g}r5N_DVVx-JUsA=qS5&cJP|LLB$ODJNyedQnx?= z8BEx*8QvIt6ATS1jIs$9f@tXX{>Y%%_|p({oTMUuRo^>)e!y2-e|(o>$-=AW$st3! zF^;4dgbfpFP`BgxgP7i@49D5ibYfoXX*%1r+l$Ao9wX8`hzXHIP9!~!&aLNjI7fZR zlv*^cG4Ep?->ZXjVcR>^f_&fN-!FKO2&82~ zl@7pAa*2vzv6t~~&d%x8)(_vFdu2XMo7!IN*zzpbuHi%3(-QpR&P+y5S4YR2g`n)i zWJ`~U4t;NI)U)* zR#v8OGT#*lVV&PINSI{FGIZYx4L-&eu+T5rH88sV<~aXYbIc_Z6O+o_ozlWUC!y1d zVa!h+KkmqP)Jptxnwi;W-74`@nqh{(DYeeZlZ=dU>KE8ddy3rc3=N|S11Wc{6RzA@ z9to9|knnCxQepF7)d>iwAUdqPtD|9r`7JkbH#IeljEq*rtz*>3r*5U214Q#L8YSNOo4t8c3Q5<8PYkJe} zTyV*undjog$g~rob$Kp5d1+}pTKA}^s3hIL+?IcWv!SdCd`g_yTCA*m|7i~$+_Y|f z55Js>fPjG6JD2I6e8*q|rXzRD%A}Z7XH@Be0?mssFSVY_usq2BI@(~Quit3iM~oAn zB*rn)wO03(UcGu%>A~5EVzJ7*(2q*&B&n{p7PnDX={~A>_wq0e4NdS7CJuA^LbrjV ztWu5X*D7y8MdmOg6bcp2Dt()x>oyhr*zOnnBt~K|aM!=UR6sl3GN%E3?$|jfyS~2u z#sLcI``iVl<<6ZK6<7#FB9TEx90rHC*~4>T?Z?=m?3hcA)c4PaDdxNOiFJv3@bK~; zuLyFOYJCZKGe7DhX2>??@>>qpKh#Y9NF*XHICDx$N{(|XQg-at&uXsk-nh%@d^bHW{HZEY2@u7WDu>6w|oue8YKXMf^6 z6{;{?2-NcN^4eG=dVHe2;^R|N#W)G_+JtfHPF^1TM!7Mk;(ZJvA@jOE&nvRVmKMg- z+d1Xmm}kk$y_UzCUc6whkgPd&PDcKKkXygRjYYML&JQJ5tTHW1qtGceH8t7h#Wf{Y zxL$cnSB<<6=GJ=FylLp|y#aidl00|qhN+oZL)aPo@|X${d9LCYjrIx zWxSV$Cng+7_+w`!hCPZw(7-{pS~Sd4qM)|6c5MF_%<7{&r^;~aE3>lKkpDW1l~Gbs z(wl6}gBeCSr~DrtIW06y6d&T}=hyET!RWM72enU+mA2?#xpKwCglU#sVHk%9rag1P z=Wy@p;?Qm|TY$B6sO>9;poGi#Wr1FhgZbH-BEIVjPk12Lwzf9s>(@A64It}^tqQ@P_TA`g7u-u0UH~e=Kpsn>d`E>d8u^l|7*#T={@TAT* z*EGwg+%l(o7FROb5RToUB5zgEOHn7xW)*_>E$l?SA8BlAGRd{Q^TU8p7rssohTzu5 z*HNW#R$@y_rQfE9oZPKKJ>znpwRlM^7(p-vf_#4&As_U~u&}TNbX|SDp@9MK(pTr* zY9HB5{Mn-oU^GSvn0=c{40jfZCACy&rp8GTmM4gD<Y8PlGdb7k_}o9r)01WC76fwC5s9Q? z3p%M|Z2UP7`4K_*0*S6nwoJ}7H#RDFC3{}^L?!_eWa?AmIMe$4K?({%%d(=Bl)Ij6 z8^Iqws8*zQ^Zc0hr>4E)>FH@|8rytpFu^j%st7XzD$;m8m~HrS+N-6H$dmZ9RU;VC zoy5+a8;L_#*jR*qa4v9gbUel^GW9vvF7vuh$?e+*N!;ma#X=!O{>a+db6P@Y;j{$YJ`hhPe)3o5? z`SZ2Gy*#HSFvDOJ^jnF?5tkW94|Qd{2+TAqB=t$hDJHsueCz4y0fUis5Gu~jh6xIy zx4*CHrD~3sDn4r|Umx_H`z-u=t6Ix{XLB+>LCn69t}B^JM;^*FoDCJMnA*H@|G|TR zt@%P4YU;B`l^lCrot!ql&*tdq>TZxw?%m(YgmN9q_;`7EhUapNiX?!r4O>u238DqR zcK@v8az;+YiR}fVhK2?(;~AU1@mnVy#v-l`>gs|8 z=)6F^L;m>Kn78*mConah4=Px2_>r~Fu4Ssx*T5kzE-uBy-1je|9zJBB6hsHV|60dr zMHxRA&|Mos5Bjx$nGLm(xp{MsnvRano(MlQK0XfaYdD*&g))tEZ#FT`gW`{T^yqSP z6=%3qTSv$FKmzsK>)kLCj9JJUnr*xNhAODec6#aD$wZ}ahXBGFDdF;Ea|V8klEnjN{RhO*%N{Bt00;n8DMsqIbp8arLx$SIL;Hl~+U!TiPpw&rSvKEW$ zlfEXw&wu~Yfr5epnYVl_6_O{S{m9aCau`34vz{~Q-~fKNHB_sh$!`%KT#e6 z2H2LEE&S4@fz+soh>@M9$!ET#?ME%LyJhHkRc=mBxzz<%r3%O%ctA`w%^J+L3wC*e zi+n$_F<&@DikGx2>`Q(cusB%me+CxM&9XYv`EmOZP`{v*=kI2O0DUL&Rq(DxO8!;+ z;vjL|kNSyffdi45BzO_o<|Gml5|Wt#xi{uArX?pUSof{JPJMP_5T4>tbDN4|X9P4d zN!jTN;R$SMTSVgd*G9sy= zSe#??)8l8(oS~`cddFD?c~#^{(B-uF}ZCXDYYn0!wcD}=EV%{_U@(4?#b zl#j%q!0oke|Mda<+Kj<^A=rb!&~Y~svsUX38`g*ubAJ#39QOWddq2QhvsbjL>c)ZH zA1hkx-M*_+IwmGfn;oYhNtL3*629N~C#Q^F>#IfaS5HxJJrsic#J`37_M0)-X>s%9 z-Vd%qa5x-;XVIp7O|ETh?7g{+Bo(%`w{tn4tTNL*6tp;72@nR~AdzW05L$&H2<*kA zZaqD{9#-VR4RIB(TfHvt9zLWi9az}u%BkD|15f*t*}c8mUUFfl&zps?(=jN78b7Q-gsB+tMR5| z4d+eFC098Sbcp5@#;f&9U8sUfojv>xP*|@0BxgSJVufXTdb%?nA=2mbSTPb>nxE_e zUu(Z*C8eZ%C^mn>&&72oC;F+BlhS5OeW@B?NSMHY9q723PDke%7b>Yx7y@Cs;{!5X z-n=z3(q25R+8PrmEF$uFkr&abLT>h4T}*x3>AG|C zdx{1P*wBt1eFjIWnwZ3#%mSYy_wOGenGI>TW*7--xt(*$H6EKz24xMJOM3c6-lzik zq;mF@f&znN-LKNun1Upm1n*I3!~Mh$peUh-cOmG1a)C=jB@;GK? z6mk-YeK$+n>n?FNq3oOP4sYMQSJpedkJmCf5eb@-sV@0FV0XEE3CUHZ#m-Jk2DQ;a z|4SEQ_##a$A)ooqN<%EmQHt3U=WmPtgDVpaWUWpj&aj=L9E+y6rUH(#z|5}XkgD(l zP%GhY0dOWcvLB$k@lP86hlu^H>i^5bZ?cifyL2xCCywv^lR!m5Q$G8e_09hPLrcp% literal 0 HcmV?d00001 diff --git a/cloud-minecraft/cloud-fabric/src/main/resources/fabric.mod.json b/cloud-minecraft/cloud-fabric/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..b332db0a --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/resources/fabric.mod.json @@ -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" + } +} diff --git a/cloud-minecraft/cloud-fabric/src/testmod/java/cloud/commandframework/fabric/testmod/FabricExample.java b/cloud-minecraft/cloud-fabric/src/testmod/java/cloud/commandframework/fabric/testmod/FabricExample.java new file mode 100644 index 00000000..f255161f --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/testmod/java/cloud/commandframework/fabric/testmod/FabricExample.java @@ -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 NAME = StringArgument.of("name"); + private static final CommandArgument HUGS = IntegerArgument.newBuilder("hugs") + .asOptionalWithDefault("1") + .build(); + + @Override + public void onInitialize() { + // Create a commands manager. We'll use native command source types for this. + + final FabricCommandManager 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); + })); + + } + +} diff --git a/cloud-minecraft/cloud-fabric/src/testmod/java/cloud/commandframework/fabric/testmod/package-info.java b/cloud-minecraft/cloud-fabric/src/testmod/java/cloud/commandframework/fabric/testmod/package-info.java new file mode 100644 index 00000000..188f9307 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/testmod/java/cloud/commandframework/fabric/testmod/package-info.java @@ -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; diff --git a/cloud-minecraft/cloud-fabric/src/testmod/resources/fabric.mod.json b/cloud-minecraft/cloud-fabric/src/testmod/resources/fabric.mod.json new file mode 100644 index 00000000..f923a9dd --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/testmod/resources/fabric.mod.json @@ -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": "*" + } +} diff --git a/gradle.properties b/gradle.properties index 3e3ee277..38464656 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ org.gradle.parallel=true -org.gradle.jvmargs=-Xmx512m +org.gradle.jvmargs=-Xmx1G diff --git a/settings.gradle.kts b/settings.gradle.kts index 63bbc266..44a910b8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,12 @@ +pluginManagement { + repositories { + maven("https://maven.fabricmc.net") { + name = "fabric" + } + gradlePluginPortal() + } +} + rootProject.name = "cloud" // Core Modules @@ -16,6 +25,7 @@ setupDiscordModule("cloud-jda") // Minecraft Modules setupMinecraftModule("cloud-brigadier") setupMinecraftModule("cloud-bukkit") +setupMinecraftModule("cloud-fabric") setupMinecraftModule("cloud-paper") setupMinecraftModule("cloud-velocity") setupMinecraftModule("cloud-sponge")