fabric: Add a couple more commands to the test mod
This commit is contained in:
parent
d72558ee81
commit
5a15ca2167
5 changed files with 297 additions and 68 deletions
|
|
@ -23,26 +23,106 @@
|
|||
//
|
||||
package cloud.commandframework.fabric.testmod;
|
||||
|
||||
import cloud.commandframework.Command;
|
||||
import cloud.commandframework.arguments.standard.StringArgument;
|
||||
import cloud.commandframework.execution.CommandExecutionCoordinator;
|
||||
import cloud.commandframework.fabric.FabricClientCommandManager;
|
||||
import cloud.commandframework.meta.CommandMeta;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.internal.Streams;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.SaveLevelScreen;
|
||||
import net.minecraft.client.gui.screen.TitleScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.realms.gui.screen.RealmsBridgeScreen;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.argument.ArgumentTypes;
|
||||
import net.minecraft.text.ClickEvent;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
|
||||
public final class FabricClientExample implements ClientModInitializer {
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
final FabricClientCommandManager<FabricClientCommandSource> commandManager =
|
||||
FabricClientCommandManager.createNative(CommandExecutionCoordinator.simpleCoordinator());
|
||||
|
||||
commandManager.command(
|
||||
commandManager.commandBuilder("cloud_client")
|
||||
.literal("say")
|
||||
.argument(StringArgument.greedy("message"))
|
||||
.handler(ctx -> ctx.getSender().sendFeedback(
|
||||
new LiteralText("Cloud client commands says: " + ctx.get("message"))
|
||||
))
|
||||
);
|
||||
final Command.Builder<FabricClientCommandSource> base = commandManager.commandBuilder("cloud_client");
|
||||
|
||||
commandManager.command(base.literal("dump")
|
||||
.meta(CommandMeta.DESCRIPTION, "Dump the client's Brigadier command tree")
|
||||
.handler(ctx -> {
|
||||
final Path target = FabricLoader.getInstance().getGameDir().resolve(
|
||||
"cloud-dump-" + Instant.now().toString().replace(':', '-') + ".json"
|
||||
);
|
||||
ctx.getSender().sendFeedback(
|
||||
new LiteralText("Dumping command output to ")
|
||||
.append(new LiteralText(target.toString())
|
||||
.styled(s -> s.withClickEvent(new ClickEvent(
|
||||
ClickEvent.Action.OPEN_FILE,
|
||||
target.toAbsolutePath().toString()
|
||||
))))
|
||||
);
|
||||
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(target); JsonWriter json = new JsonWriter(writer)) {
|
||||
final CommandDispatcher<CommandSource> dispatcher = MinecraftClient.getInstance()
|
||||
.getNetworkHandler()
|
||||
.getCommandDispatcher();
|
||||
final JsonObject object = ArgumentTypes.toJson(dispatcher, dispatcher.getRoot());
|
||||
json.setIndent(" ");
|
||||
Streams.write(object, json);
|
||||
} catch (final IOException ex) {
|
||||
ctx.getSender().sendError(new LiteralText(
|
||||
"Unable to write file, see console for details: " + ex.getMessage()
|
||||
));
|
||||
}
|
||||
}));
|
||||
|
||||
commandManager.command(base.literal("say")
|
||||
.argument(StringArgument.greedy("message"))
|
||||
.handler(ctx -> ctx.getSender().sendFeedback(
|
||||
new LiteralText("Cloud client commands says: " + ctx.get("message"))
|
||||
)));
|
||||
|
||||
commandManager.command(base.literal("quit")
|
||||
.handler(ctx -> {
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
disconnectClient(client);
|
||||
client.scheduleStop();
|
||||
}));
|
||||
|
||||
commandManager.command(base.literal("disconnect")
|
||||
.handler(ctx -> disconnectClient(MinecraftClient.getInstance())));
|
||||
}
|
||||
|
||||
private static void disconnectClient(final @NonNull MinecraftClient client) {
|
||||
boolean singlePlayer = client.isInSingleplayer();
|
||||
client.world.disconnect();
|
||||
if (singlePlayer) {
|
||||
client.disconnect(new SaveLevelScreen(new TranslatableText("menu.savingLevel")));
|
||||
} else {
|
||||
client.disconnect();
|
||||
}
|
||||
if (singlePlayer) {
|
||||
client.openScreen(new TitleScreen());
|
||||
} else if (client.isConnectedToRealms()) {
|
||||
new RealmsBridgeScreen().switchToRealms(new TitleScreen());
|
||||
} else {
|
||||
client.openScreen(new MultiplayerScreen(new TitleScreen()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,112 +26,197 @@ package cloud.commandframework.fabric.testmod;
|
|||
|
||||
import cloud.commandframework.Command;
|
||||
import cloud.commandframework.arguments.CommandArgument;
|
||||
import cloud.commandframework.arguments.parser.ArgumentParseResult;
|
||||
import cloud.commandframework.arguments.standard.IntegerArgument;
|
||||
import cloud.commandframework.arguments.standard.StringArgument;
|
||||
import cloud.commandframework.execution.CommandExecutionCoordinator;
|
||||
import cloud.commandframework.fabric.FabricServerCommandManager;
|
||||
import cloud.commandframework.fabric.argument.ColorArgument;
|
||||
import cloud.commandframework.fabric.argument.ItemDataArgument;
|
||||
import cloud.commandframework.fabric.argument.server.MultiplePlayerSelectorArgument;
|
||||
import cloud.commandframework.fabric.data.MultiplePlayerSelector;
|
||||
import cloud.commandframework.meta.CommandMeta;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.internal.Streams;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import cloud.commandframework.fabric.testmod.mixin.GiveCommandAccess;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.argument.ArgumentTypes;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||
import net.fabricmc.loader.api.metadata.Person;
|
||||
import net.minecraft.command.argument.ItemStackArgument;
|
||||
import net.minecraft.network.MessageType;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.ClickEvent;
|
||||
import net.minecraft.text.HoverEvent;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.TextColor;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.Util;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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();
|
||||
private static final CommandArgument<ServerCommandSource, MultiplePlayerSelector> PLAYER_SELECTOR =
|
||||
MultiplePlayerSelectorArgument.of("players");
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
// Create a commands manager. We'll use native command source types for this.
|
||||
|
||||
final FabricServerCommandManager<ServerCommandSource> manager =
|
||||
FabricServerCommandManager.createNative(CommandExecutionCoordinator.simpleCoordinator());
|
||||
|
||||
final Command.Builder<ServerCommandSource> base = manager.commandBuilder("cloudtest");
|
||||
|
||||
final CommandArgument<ServerCommandSource, String> name = StringArgument.of("name");
|
||||
final CommandArgument<ServerCommandSource, Integer> hugs = IntegerArgument.<ServerCommandSource>newBuilder("hugs")
|
||||
.asOptionalWithDefault("1")
|
||||
.build();
|
||||
|
||||
manager.command(base
|
||||
.argument(NAME)
|
||||
.argument(HUGS)
|
||||
.literal("hugs")
|
||||
.argument(name)
|
||||
.argument(hugs)
|
||||
.handler(ctx -> {
|
||||
ctx.getSender().sendFeedback(new LiteralText("Hello, ")
|
||||
.append(ctx.get(NAME))
|
||||
.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)))
|
||||
.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);
|
||||
}));
|
||||
|
||||
manager.command(base.literal("dump")
|
||||
.meta(CommandMeta.DESCRIPTION, "Dump the client's Brigadier command tree (integrated server only)")
|
||||
.meta(FabricServerCommandManager.META_REGISTRATION_ENVIRONMENT, CommandManager.RegistrationEnvironment.INTEGRATED)
|
||||
.handler(ctx -> {
|
||||
final Path target =
|
||||
FabricLoader.getInstance().getGameDir().resolve(
|
||||
"cloud-dump-"
|
||||
+ Instant.now().toString().replace(':', '-')
|
||||
+ ".json"
|
||||
);
|
||||
ctx.getSender().sendFeedback(new LiteralText("Dumping command output to ")
|
||||
.append(new LiteralText(target.toString())
|
||||
.styled(s -> s.withClickEvent(new ClickEvent(
|
||||
ClickEvent.Action.OPEN_FILE,
|
||||
target.toAbsolutePath().toString()
|
||||
)))), false);
|
||||
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(target); JsonWriter json = new JsonWriter(writer)) {
|
||||
final CommandDispatcher<CommandSource> dispatcher = MinecraftClient.getInstance()
|
||||
.getNetworkHandler()
|
||||
.getCommandDispatcher();
|
||||
final JsonObject object = ArgumentTypes.toJson(dispatcher, dispatcher.getRoot());
|
||||
json.setIndent(" ");
|
||||
Streams.write(object, json);
|
||||
} catch (final IOException ex) {
|
||||
ctx.getSender().sendError(new LiteralText("Unable to write file, see console for details: " + ex.getMessage()));
|
||||
}
|
||||
}));
|
||||
final CommandArgument<ServerCommandSource, MultiplePlayerSelector> playerSelector =
|
||||
MultiplePlayerSelectorArgument.of("players");
|
||||
final CommandArgument<ServerCommandSource, Formatting> textColor = ColorArgument.of("color");
|
||||
|
||||
manager.command(base.literal("wave")
|
||||
.argument(PLAYER_SELECTOR)
|
||||
.argument(playerSelector)
|
||||
.argument(textColor)
|
||||
.handler(ctx -> {
|
||||
final MultiplePlayerSelector selector = ctx.get(PLAYER_SELECTOR);
|
||||
final MultiplePlayerSelector selector = ctx.get(playerSelector);
|
||||
final Collection<ServerPlayerEntity> selected = selector.get();
|
||||
selected.forEach(selectedPlayer ->
|
||||
selectedPlayer.sendMessage(new LiteralText("Wave"), MessageType.SYSTEM, Util.NIL_UUID));
|
||||
ctx.getSender().sendFeedback(new LiteralText(String.format("Waved at %d players (%s)", selected.size(),
|
||||
selector.getInput())),
|
||||
false);
|
||||
selectedPlayer.sendMessage(
|
||||
new LiteralText("Wave from ")
|
||||
.styled(style -> style.withColor(ctx.get(textColor)))
|
||||
.append(ctx.getSender().getDisplayName()),
|
||||
MessageType.SYSTEM,
|
||||
Util.NIL_UUID
|
||||
));
|
||||
ctx.getSender().sendFeedback(
|
||||
new LiteralText(String.format("Waved at %d players (%s)", selected.size(),
|
||||
selector.getInput()
|
||||
)),
|
||||
false
|
||||
);
|
||||
}));
|
||||
|
||||
manager.command(base.literal("give")
|
||||
.permission("cloud.give")
|
||||
.argument(MultiplePlayerSelectorArgument.of("targets"))
|
||||
.argument(ItemDataArgument.of("item"))
|
||||
.argument(IntegerArgument.<ServerCommandSource>newBuilder("amount")
|
||||
.withMin(1)
|
||||
.asOptionalWithDefault("1"))
|
||||
.handler(ctx -> {
|
||||
final ItemStackArgument item = ctx.get("item");
|
||||
final MultiplePlayerSelector targets = ctx.get("targets");
|
||||
final int amount = ctx.get("amount");
|
||||
GiveCommandAccess.give(
|
||||
ctx.getSender(),
|
||||
item,
|
||||
targets.get(),
|
||||
amount
|
||||
);
|
||||
}));
|
||||
|
||||
final Command.Builder<ServerCommandSource> mods = base.literal("mods").permission("cloud.mods");
|
||||
|
||||
manager.command(mods.handler(ctx -> {
|
||||
final List<ModMetadata> modList = FabricLoader.getInstance().getAllMods().stream()
|
||||
.map(ModContainer::getMetadata)
|
||||
.sorted(Comparator.comparing(ModMetadata::getId))
|
||||
.collect(Collectors.toList());
|
||||
final LiteralText text = new LiteralText("");
|
||||
text.append(new LiteralText("Loaded Mods")
|
||||
.styled(style -> style.withColor(Formatting.BLUE).withFormatting(Formatting.BOLD)));
|
||||
text.append(new LiteralText(String.format(" (%s)\n", modList.size()))
|
||||
.styled(style -> style.withColor(Formatting.GRAY).withFormatting(Formatting.ITALIC)));
|
||||
for (final ModMetadata mod : modList) {
|
||||
text.append(
|
||||
new LiteralText("")
|
||||
.styled(style -> style.withColor(Formatting.WHITE)
|
||||
.withClickEvent(new ClickEvent(
|
||||
ClickEvent.Action.SUGGEST_COMMAND,
|
||||
String.format("/cloudtest mods %s", mod.getId())
|
||||
))
|
||||
.withHoverEvent(new HoverEvent(
|
||||
HoverEvent.Action.SHOW_TEXT,
|
||||
new LiteralText("Click for more info")
|
||||
)))
|
||||
.append(new LiteralText(mod.getName()).styled(style -> style.withColor(Formatting.GREEN)))
|
||||
.append(new LiteralText(String.format(" (%s) ", mod.getId()))
|
||||
.styled(style -> style.withColor(Formatting.GRAY).withFormatting(Formatting.ITALIC)))
|
||||
.append(new LiteralText(String.format("v%s", mod.getVersion())))
|
||||
);
|
||||
if (modList.indexOf(mod) != modList.size() - 1) {
|
||||
text.append(new LiteralText(", ").styled(style -> style.withColor(Formatting.GRAY)));
|
||||
}
|
||||
}
|
||||
ctx.getSender().sendFeedback(text, false);
|
||||
}));
|
||||
|
||||
final CommandArgument<ServerCommandSource, ModMetadata> modMetadata = manager.argumentBuilder(ModMetadata.class, "mod")
|
||||
.withSuggestionsProvider((ctx, input) -> FabricLoader.getInstance().getAllMods().stream()
|
||||
.map(ModContainer::getMetadata)
|
||||
.map(ModMetadata::getId)
|
||||
.collect(Collectors.toList()))
|
||||
.withParser((ctx, inputQueue) -> {
|
||||
final ModMetadata meta = FabricLoader.getInstance().getModContainer(inputQueue.peek())
|
||||
.map(ModContainer::getMetadata)
|
||||
.orElse(null);
|
||||
if (meta != null) {
|
||||
inputQueue.remove();
|
||||
return ArgumentParseResult.success(meta);
|
||||
}
|
||||
return ArgumentParseResult.failure(new IllegalArgumentException(String.format(
|
||||
"No mod with id '%s'",
|
||||
inputQueue.peek()
|
||||
)));
|
||||
})
|
||||
.build();
|
||||
|
||||
manager.command(mods.argument(modMetadata)
|
||||
.handler(ctx -> {
|
||||
final ModMetadata meta = ctx.get(modMetadata);
|
||||
final MutableText text = new LiteralText("")
|
||||
.append(new LiteralText(meta.getName())
|
||||
.styled(style -> style.withColor(Formatting.BLUE).withFormatting(Formatting.BOLD)))
|
||||
.append(new LiteralText("\n modid: " + meta.getId()))
|
||||
.append(new LiteralText("\n version: " + meta.getVersion()))
|
||||
.append(new LiteralText("\n type: " + meta.getType()));
|
||||
|
||||
if (!meta.getDescription().isEmpty()) {
|
||||
text.append(new LiteralText("\n description: " + meta.getDescription()));
|
||||
}
|
||||
if (!meta.getAuthors().isEmpty()) {
|
||||
text.append(new LiteralText("\n authors: " + meta.getAuthors().stream()
|
||||
.map(Person::getName)
|
||||
.collect(Collectors.joining(", "))));
|
||||
}
|
||||
if (!meta.getLicense().isEmpty()) {
|
||||
text.append(new LiteralText("\n license: " + String.join(", ", meta.getLicense())));
|
||||
}
|
||||
ctx.getSender().sendFeedback(
|
||||
text,
|
||||
false
|
||||
);
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2021 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.mixin;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import net.minecraft.command.argument.ItemStackArgument;
|
||||
import net.minecraft.server.command.GiveCommand;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@Mixin(GiveCommand.class)
|
||||
public interface GiveCommandAccess {
|
||||
|
||||
@Invoker("execute")
|
||||
static int give(
|
||||
final ServerCommandSource source,
|
||||
final ItemStackArgument item,
|
||||
final Collection<ServerPlayerEntity> targets,
|
||||
final int count
|
||||
) {
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"package": "cloud.commandframework.fabric.testmod.mixin",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"required": true,
|
||||
"mixins": [
|
||||
"GiveCommandAccess"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
"name": "Cloud Test mod",
|
||||
"description": "Command framework and dispatcher for the JVM",
|
||||
"authors": [ "Citomonstret", "zml" ],
|
||||
"authors": [ "Citymonstret", "zml" ],
|
||||
"contact": {
|
||||
"homepage": "https://commandframework.cloud/",
|
||||
"sources": "https://github.com/Incendo/cloud"
|
||||
|
|
@ -22,6 +22,10 @@
|
|||
]
|
||||
},
|
||||
|
||||
"mixins": [
|
||||
"cloud-testmod.mixins.json"
|
||||
],
|
||||
|
||||
"depends": {
|
||||
"fabricloader": ">=0.7.4",
|
||||
"fabric-command-api-v1": "*",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue