fabric: Support 1.19 (#356)
Co-authored-by: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
This commit is contained in:
parent
28ff5d3003
commit
63f2c9299f
21 changed files with 370 additions and 199 deletions
|
|
@ -26,6 +26,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Paper: Improved KeyedWorldArgument suggestions ([#334](https://github.com/Incendo/cloud/pull/334))
|
||||
- Minecraft: Support sender-aware description decorators in MinecraftHelp ([#354](https://github.com/Incendo/cloud/pull/354))
|
||||
|
||||
### Changed
|
||||
- Fabric: Updated for Minecraft 1.19 (no longer supports older versions)
|
||||
|
||||
## [1.6.2]
|
||||
|
||||
### Fixed
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
// loom needs this version of asm, for some reason we have an older one on the classpath without this
|
||||
implementation("org.ow2.asm:asm:9.3")
|
||||
implementation(libs.indraCommon)
|
||||
implementation(libs.indraPublishingSonatype)
|
||||
implementation(libs.gradleTestLogger)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Supplier;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
|
@ -53,7 +54,7 @@ public final class WrappedBrigadierParser<C, T> implements ArgumentParser<C, T>
|
|||
|
||||
public static final String COMMAND_CONTEXT_BRIGADIER_NATIVE_SENDER = "_cloud_brigadier_native_sender";
|
||||
|
||||
private final ArgumentType<T> nativeType;
|
||||
private final Supplier<ArgumentType<T>> nativeType;
|
||||
private final int expectedArgumentCount;
|
||||
|
||||
/**
|
||||
|
|
@ -63,6 +64,16 @@ public final class WrappedBrigadierParser<C, T> implements ArgumentParser<C, T>
|
|||
* @since 1.5.0
|
||||
*/
|
||||
public WrappedBrigadierParser(final ArgumentType<T> nativeType) {
|
||||
this(() -> nativeType, DEFAULT_ARGUMENT_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an argument parser based on a brigadier command.
|
||||
*
|
||||
* @param nativeType the native command type, computed lazily
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public WrappedBrigadierParser(final Supplier<ArgumentType<T>> nativeType) {
|
||||
this(nativeType, DEFAULT_ARGUMENT_COUNT);
|
||||
}
|
||||
|
||||
|
|
@ -74,10 +85,25 @@ public final class WrappedBrigadierParser<C, T> implements ArgumentParser<C, T>
|
|||
* @since 1.5.0
|
||||
*/
|
||||
public WrappedBrigadierParser(
|
||||
final ArgumentType<T> nativeType,
|
||||
final ArgumentType<T> nativeType,
|
||||
final int expectedArgumentCount
|
||||
) {
|
||||
this(() -> nativeType, expectedArgumentCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an argument parser based on a brigadier command.
|
||||
*
|
||||
* @param nativeType the native command type provider, calculated lazily
|
||||
* @param expectedArgumentCount the number of arguments the brigadier type is expected to consume
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public WrappedBrigadierParser(
|
||||
final Supplier<ArgumentType<T>> nativeType,
|
||||
final int expectedArgumentCount
|
||||
) {
|
||||
this.nativeType = requireNonNull(nativeType, "brigadierType");
|
||||
requireNonNull(nativeType, "brigadierType");
|
||||
this.nativeType = nativeType;
|
||||
this.expectedArgumentCount = expectedArgumentCount;
|
||||
}
|
||||
|
||||
|
|
@ -88,7 +114,7 @@ public final class WrappedBrigadierParser<C, T> implements ArgumentParser<C, T>
|
|||
* @since 1.5.0
|
||||
*/
|
||||
public ArgumentType<T> getNativeArgument() {
|
||||
return this.nativeType;
|
||||
return this.nativeType.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -109,7 +135,7 @@ public final class WrappedBrigadierParser<C, T> implements ArgumentParser<C, T>
|
|||
|
||||
// Then try to parse
|
||||
try {
|
||||
return ArgumentParseResult.success(this.nativeType.parse(reader));
|
||||
return ArgumentParseResult.success(this.nativeType.get().parse(reader));
|
||||
} catch (final CommandSyntaxException ex) {
|
||||
return ArgumentParseResult.failure(ex);
|
||||
} finally {
|
||||
|
|
@ -142,7 +168,7 @@ public final class WrappedBrigadierParser<C, T> implements ArgumentParser<C, T>
|
|||
false
|
||||
);
|
||||
|
||||
final CompletableFuture<Suggestions> result = this.nativeType.listSuggestions(
|
||||
final CompletableFuture<Suggestions> result = this.nativeType.get().listSuggestions(
|
||||
reverseMappedContext,
|
||||
new SuggestionsBuilder(input, 0)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import net.fabricmc.loom.task.AbstractRunTask
|
|||
import net.ltgt.gradle.errorprone.errorprone
|
||||
|
||||
plugins {
|
||||
id("quiet-fabric-loom") version "0.11-SNAPSHOT"
|
||||
id("quiet-fabric-loom") version "0.12-SNAPSHOT"
|
||||
id("cloud.base-conventions")
|
||||
}
|
||||
|
||||
|
|
@ -44,7 +44,8 @@ dependencies {
|
|||
minecraft(libs.fabricMinecraft)
|
||||
mappings(loom.officialMojangMappings())
|
||||
modImplementation(libs.fabricLoader)
|
||||
modImplementation(fabricApi.module("fabric-command-api-v1", libs.versions.fabricApi.get()))
|
||||
modImplementation(fabricApi.module("fabric-command-api-v2", libs.versions.fabricApi.get()))
|
||||
modImplementation(fabricApi.module("fabric-networking-api-v1", libs.versions.fabricApi.get()))
|
||||
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", libs.versions.fabricApi.get()))
|
||||
|
||||
modImplementation(libs.fabricPermissionsApi)
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import cloud.commandframework.execution.AsynchronousCommandExecutionCoordinator;
|
|||
import cloud.commandframework.execution.CommandExecutionCoordinator;
|
||||
import cloud.commandframework.permission.PredicatePermission;
|
||||
import java.util.function.Function;
|
||||
import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource;
|
||||
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientSuggestionProvider;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
|
@ -165,7 +165,8 @@ public final class FabricClientCommandManager<C> extends FabricCommandManager<C,
|
|||
if (!Minecraft.getInstance().hasSingleplayerServer()) {
|
||||
return allowOnMultiplayer;
|
||||
}
|
||||
return Minecraft.getInstance().getSingleplayerServer().getPlayerList().isAllowCheatsForAllPlayers();
|
||||
return Minecraft.getInstance().getSingleplayerServer().getPlayerList().isAllowCheatsForAllPlayers()
|
||||
|| Minecraft.getInstance().getSingleplayerServer().getWorldData().getAllowCommands();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -198,7 +199,8 @@ public final class FabricClientCommandManager<C> extends FabricCommandManager<C,
|
|||
if (!Minecraft.getInstance().hasSingleplayerServer()) {
|
||||
return allowOnMultiplayer;
|
||||
}
|
||||
return !Minecraft.getInstance().getSingleplayerServer().getPlayerList().isAllowCheatsForAllPlayers();
|
||||
return !Minecraft.getInstance().getSingleplayerServer().getPlayerList().isAllowCheatsForAllPlayers()
|
||||
&& !Minecraft.getInstance().getSingleplayerServer().getWorldData().getAllowCommands();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import cloud.commandframework.meta.CommandMeta;
|
|||
import cloud.commandframework.meta.SimpleCommandMeta;
|
||||
import cloud.commandframework.permission.PredicatePermission;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||
import com.mojang.serialization.Codec;
|
||||
import io.leangen.geantyref.GenericTypeReflector;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
|
|
@ -56,16 +55,13 @@ import java.util.function.Function;
|
|||
import java.util.function.Supplier;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.advancements.critereon.MinMaxBounds;
|
||||
import net.minecraft.commands.CommandBuildContext;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.commands.arguments.AngleArgument;
|
||||
import net.minecraft.commands.arguments.ColorArgument;
|
||||
import net.minecraft.commands.arguments.CompoundTagArgument;
|
||||
import net.minecraft.commands.arguments.DimensionArgument;
|
||||
import net.minecraft.commands.arguments.EntityAnchorArgument;
|
||||
import net.minecraft.commands.arguments.EntitySummonArgument;
|
||||
import net.minecraft.commands.arguments.ItemEnchantmentArgument;
|
||||
import net.minecraft.commands.arguments.MessageArgument;
|
||||
import net.minecraft.commands.arguments.MobEffectArgument;
|
||||
import net.minecraft.commands.arguments.NbtPathArgument;
|
||||
import net.minecraft.commands.arguments.NbtTagArgument;
|
||||
import net.minecraft.commands.arguments.ObjectiveCriteriaArgument;
|
||||
|
|
@ -73,12 +69,12 @@ import net.minecraft.commands.arguments.OperationArgument;
|
|||
import net.minecraft.commands.arguments.ParticleArgument;
|
||||
import net.minecraft.commands.arguments.RangeArgument;
|
||||
import net.minecraft.commands.arguments.ResourceLocationArgument;
|
||||
import net.minecraft.commands.arguments.ResourceOrTagLocationArgument;
|
||||
import net.minecraft.commands.arguments.UuidArgument;
|
||||
import net.minecraft.commands.arguments.blocks.BlockPredicateArgument;
|
||||
import net.minecraft.commands.arguments.coordinates.SwizzleArgument;
|
||||
import net.minecraft.commands.arguments.item.ItemArgument;
|
||||
import net.minecraft.commands.arguments.item.ItemInput;
|
||||
import net.minecraft.commands.synchronization.SuggestionProviders;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.particles.ParticleOptions;
|
||||
|
|
@ -180,64 +176,26 @@ public abstract class FabricCommandManager<C, S extends SharedSuggestionProvider
|
|||
this.registerConstantNativeParserSupplier(OperationArgument.Operation.class, OperationArgument.operation());
|
||||
this.registerConstantNativeParserSupplier(ParticleOptions.class, ParticleArgument.particle());
|
||||
this.registerConstantNativeParserSupplier(AngleArgument.SingleAngle.class, AngleArgument.angle());
|
||||
this.registerConstantNativeParserSupplier(new TypeToken<EnumSet<Direction.Axis>>() {
|
||||
}, SwizzleArgument.swizzle());
|
||||
this.registerConstantNativeParserSupplier(new TypeToken<EnumSet<Direction.Axis>>() {}, SwizzleArgument.swizzle());
|
||||
this.registerConstantNativeParserSupplier(ResourceLocation.class, ResourceLocationArgument.id());
|
||||
this.registerConstantNativeParserSupplier(
|
||||
EntityAnchorArgument.Anchor.class,
|
||||
EntityAnchorArgument.anchor()
|
||||
);
|
||||
this.registerConstantNativeParserSupplier(EntityAnchorArgument.Anchor.class, EntityAnchorArgument.anchor());
|
||||
this.registerConstantNativeParserSupplier(MinMaxBounds.Ints.class, RangeArgument.intRange());
|
||||
this.registerConstantNativeParserSupplier(MinMaxBounds.Floats.class, RangeArgument.floatRange());
|
||||
this.registerConstantNativeParserSupplier(ItemInput.class, ItemArgument.item());
|
||||
this.registerConstantNativeParserSupplier(MinMaxBounds.Doubles.class, RangeArgument.floatRange());
|
||||
this.registerContextualNativeParserSupplier(ItemInput.class, ItemArgument::item);
|
||||
this.registerContextualNativeParserSupplier(BlockPredicateArgument.Result.class, BlockPredicateArgument::blockPredicate);
|
||||
|
||||
/* Wrapped/Constant Brigadier types, mapped value type */
|
||||
this.registerConstantNativeParserSupplier(
|
||||
BlockPredicateArgument.Result.class,
|
||||
BlockPredicateArgument.blockPredicate()
|
||||
);
|
||||
this.registerConstantNativeParserSupplier(MessageArgument.Message.class, MessageArgument.message());
|
||||
this.getParserRegistry().registerParserSupplier(
|
||||
TypeToken.get(MinecraftTime.class),
|
||||
params -> FabricArgumentParsers.time()
|
||||
);
|
||||
this.getParserRegistry().registerParserSupplier(TypeToken.get(MinecraftTime.class), params -> FabricArgumentParsers.time());
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private void registerRegistryEntryMappings() {
|
||||
this.brigadierManager.registerMapping(
|
||||
new TypeToken<RegistryEntryArgument.Parser<C, ?>>() {
|
||||
},
|
||||
builder -> builder.to(argument -> {
|
||||
/* several registries have specialized argument types, so let's use those where possible */
|
||||
final ResourceKey<? extends Registry<?>> registry = argument.registryKey();
|
||||
if (registry.equals(Registry.ENTITY_TYPE_REGISTRY)) {
|
||||
return EntitySummonArgument.id();
|
||||
} else if (registry.equals(Registry.ENCHANTMENT_REGISTRY)) {
|
||||
return ItemEnchantmentArgument.enchantment();
|
||||
} else if (registry.equals(Registry.MOB_EFFECT_REGISTRY)) {
|
||||
return MobEffectArgument.effect();
|
||||
} else if (registry.equals(Registry.DIMENSION_REGISTRY)) {
|
||||
return DimensionArgument.dimension();
|
||||
}
|
||||
return ResourceLocationArgument.id();
|
||||
}
|
||||
).suggestedBy((argument, useCloud) -> {
|
||||
/* A few other registries have client-side suggestion providers but no argument type */
|
||||
/* Type parameters are messed up here for some reason */
|
||||
final ResourceKey<? extends Registry<?>> registry = argument.registryKey();
|
||||
if (registry.equals(Registry.SOUND_EVENT_REGISTRY)) {
|
||||
return (SuggestionProvider<S>) SuggestionProviders.AVAILABLE_SOUNDS;
|
||||
} else if (registry.equals(Registry.BIOME_REGISTRY)) {
|
||||
return (SuggestionProvider<S>) SuggestionProviders.AVAILABLE_BIOMES;
|
||||
} else if (registry.equals(Registry.ENTITY_TYPE_REGISTRY)
|
||||
|| registry.equals(Registry.ENCHANTMENT_REGISTRY)
|
||||
|| registry.equals(Registry.MOB_EFFECT_REGISTRY)
|
||||
|| registry.equals(Registry.DIMENSION_REGISTRY)) {
|
||||
return null; /* for types with their own argument type, use Brigadier */
|
||||
}
|
||||
return useCloud; /* use cloud suggestions for anything else */
|
||||
})
|
||||
new TypeToken<RegistryEntryArgument.Parser<C, ?>>() {},
|
||||
builder -> {
|
||||
builder.to(argument -> ResourceOrTagLocationArgument.<Object>resourceOrTag((ResourceKey) argument.registryKey()));
|
||||
}
|
||||
);
|
||||
|
||||
/* Find all fields of RegistryKey<? extends Registry<?>> and register those */
|
||||
|
|
@ -292,6 +250,21 @@ public abstract class FabricCommandManager<C, S extends SharedSuggestionProvider
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a parser supplier for a brigadier type that has no options and whose output can be directly used.
|
||||
*
|
||||
* @param type the Java type to map
|
||||
* @param argument a function providing the Brigadier parser given a build context
|
||||
* @param <T> value type
|
||||
* @since 1.7.0
|
||||
*/
|
||||
final <T> void registerContextualNativeParserSupplier(
|
||||
final @NonNull Class<T> type,
|
||||
final @NonNull Function<CommandBuildContext, @NonNull ArgumentType<T>> argument
|
||||
) {
|
||||
this.getParserRegistry().registerParserSupplier(TypeToken.get(type), params -> FabricArgumentParsers.contextual(argument));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a parser supplier for a brigadier type that has no options and whose output can be directly used.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ package cloud.commandframework.fabric;
|
|||
|
||||
import cloud.commandframework.Command;
|
||||
import cloud.commandframework.arguments.StaticArgument;
|
||||
import cloud.commandframework.fabric.argument.FabricArgumentParsers;
|
||||
import cloud.commandframework.internal.CommandRegistrationHandler;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
|
|
@ -33,11 +34,16 @@ import com.mojang.brigadier.tree.LiteralCommandNode;
|
|||
import com.mojang.brigadier.tree.RootCommandNode;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import net.fabricmc.fabric.api.client.command.v1.ClientCommandManager;
|
||||
import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource;
|
||||
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
|
||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.commands.CommandBuildContext;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands.CommandSelection;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
|
@ -51,6 +57,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
* @param <S> native sender type
|
||||
*/
|
||||
abstract class FabricCommandRegistrationHandler<C, S extends SharedSuggestionProvider> implements CommandRegistrationHandler {
|
||||
|
||||
private @MonotonicNonNull FabricCommandManager<C, S> commandManager;
|
||||
|
||||
void initialize(final FabricCommandManager<C, S> manager) {
|
||||
|
|
@ -71,7 +78,7 @@ abstract class FabricCommandRegistrationHandler<C, S extends SharedSuggestionPro
|
|||
*
|
||||
* @param alias the command alias
|
||||
* @param destination the destination node
|
||||
* @param <S> brig sender type
|
||||
* @param <S> brig sender type
|
||||
* @return the built node
|
||||
*/
|
||||
private static <S> LiteralCommandNode<S> buildRedirect(
|
||||
|
|
@ -81,7 +88,7 @@ abstract class FabricCommandRegistrationHandler<C, S extends SharedSuggestionPro
|
|||
// Redirects only work for nodes with children, but break the top argument-less command.
|
||||
// Manually adding the root command after setting the redirect doesn't fix it.
|
||||
// (See https://github.com/Mojang/brigadier/issues/46) Manually clone the node instead.
|
||||
LiteralArgumentBuilder<S> builder = LiteralArgumentBuilder
|
||||
final LiteralArgumentBuilder<S> builder = LiteralArgumentBuilder
|
||||
.<S>literal(alias)
|
||||
.requires(destination.getRequirement())
|
||||
.forward(
|
||||
|
|
@ -97,19 +104,65 @@ abstract class FabricCommandRegistrationHandler<C, S extends SharedSuggestionPro
|
|||
}
|
||||
|
||||
static class Client<C> extends FabricCommandRegistrationHandler<C, FabricClientCommandSource> {
|
||||
|
||||
private final Set<Command<C>> registeredCommands = ConcurrentHashMap.newKeySet();
|
||||
private volatile boolean registerEventFired = false;
|
||||
|
||||
@Override
|
||||
void initialize(final FabricCommandManager<C, FabricClientCommandSource> manager) {
|
||||
super.initialize(manager);
|
||||
ClientCommandRegistrationCallback.EVENT.register(this::registerCommands);
|
||||
ClientPlayConnectionEvents.DISCONNECT.register(($, $$) -> this.registerEventFired = false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean registerCommand(final @NonNull Command<?> cmd) {
|
||||
final Command<C> command = (Command<C>) cmd;
|
||||
final RootCommandNode<FabricClientCommandSource> rootNode = ClientCommandManager.DISPATCHER.getRoot();
|
||||
public boolean registerCommand(final @NonNull Command<?> command) {
|
||||
this.registeredCommands.add((Command<C>) command);
|
||||
if (this.registerEventFired) {
|
||||
final ClientPacketListener connection = Minecraft.getInstance().getConnection();
|
||||
if (connection == null) {
|
||||
throw new IllegalStateException("Expected connection to be present but it wasn't!");
|
||||
}
|
||||
final CommandDispatcher<FabricClientCommandSource> dispatcher = ClientCommandManager.getActiveDispatcher();
|
||||
if (dispatcher == null) {
|
||||
throw new IllegalStateException("Expected an active dispatcher!");
|
||||
}
|
||||
FabricArgumentParsers.ContextualArgumentTypeProvider.withBuildContext(
|
||||
this.commandManager(),
|
||||
new CommandBuildContext(connection.registryAccess()),
|
||||
false,
|
||||
() -> this.registerClientCommand(dispatcher, (Command<C>) command)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void registerCommands(
|
||||
final CommandDispatcher<FabricClientCommandSource> dispatcher,
|
||||
final CommandBuildContext commandBuildContext
|
||||
) {
|
||||
this.registerEventFired = true;
|
||||
FabricArgumentParsers.ContextualArgumentTypeProvider.withBuildContext(
|
||||
this.commandManager(),
|
||||
commandBuildContext,
|
||||
true,
|
||||
() -> {
|
||||
for (final Command<C> command : this.registeredCommands) {
|
||||
this.registerClientCommand(dispatcher, command);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void registerClientCommand(
|
||||
final CommandDispatcher<FabricClientCommandSource> dispatcher,
|
||||
final Command<C> command
|
||||
) {
|
||||
final RootCommandNode<FabricClientCommandSource> rootNode = dispatcher.getRoot();
|
||||
final StaticArgument<C> first = ((StaticArgument<C>) command.getArguments().get(0));
|
||||
final CommandNode<FabricClientCommandSource> baseNode = this
|
||||
.commandManager()
|
||||
final CommandNode<FabricClientCommandSource> baseNode = this.commandManager()
|
||||
.brigadierManager()
|
||||
.createLiteralCommandNode(
|
||||
first.getName(),
|
||||
|
|
@ -131,11 +184,11 @@ abstract class FabricCommandRegistrationHandler<C, S extends SharedSuggestionPro
|
|||
for (final String alias : first.getAlternativeAliases()) {
|
||||
rootNode.addChild(buildRedirect(alias, baseNode));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class Server<C> extends FabricCommandRegistrationHandler<C, CommandSourceStack> {
|
||||
|
||||
private final Set<Command<C>> registeredCommands = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Override
|
||||
|
|
@ -150,21 +203,32 @@ abstract class FabricCommandRegistrationHandler<C, S extends SharedSuggestionPro
|
|||
return this.registeredCommands.add((Command<C>) command);
|
||||
}
|
||||
|
||||
private void registerAllCommands(final CommandDispatcher<CommandSourceStack> dispatcher, final boolean isDedicated) {
|
||||
private void registerAllCommands(
|
||||
final CommandDispatcher<CommandSourceStack> dispatcher,
|
||||
final CommandBuildContext access,
|
||||
final Commands.CommandSelection side
|
||||
) {
|
||||
this.commandManager().registrationCalled();
|
||||
for (final Command<C> command : this.registeredCommands) {
|
||||
/* Only register commands in the declared environment */
|
||||
final CommandSelection env = command.getCommandMeta().getOrDefault(
|
||||
FabricServerCommandManager.META_REGISTRATION_ENVIRONMENT,
|
||||
CommandSelection.ALL
|
||||
);
|
||||
FabricArgumentParsers.ContextualArgumentTypeProvider.withBuildContext(
|
||||
this.commandManager(),
|
||||
access,
|
||||
true,
|
||||
() -> {
|
||||
for (final Command<C> command : this.registeredCommands) {
|
||||
/* Only register commands in the declared environment */
|
||||
final Commands.CommandSelection env = command.getCommandMeta().getOrDefault(
|
||||
FabricServerCommandManager.META_REGISTRATION_ENVIRONMENT,
|
||||
Commands.CommandSelection.ALL
|
||||
);
|
||||
|
||||
if ((env == CommandSelection.INTEGRATED && isDedicated)
|
||||
|| (env == CommandSelection.DEDICATED && !isDedicated)) {
|
||||
continue;
|
||||
if ((env == Commands.CommandSelection.INTEGRATED && !side.includeIntegrated)
|
||||
|| (env == Commands.CommandSelection.DEDICATED && !side.includeDedicated)) {
|
||||
continue;
|
||||
}
|
||||
this.registerCommand(dispatcher.getRoot(), command);
|
||||
}
|
||||
}
|
||||
this.registerCommand(dispatcher.getRoot(), command);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void registerCommand(final RootCommandNode<CommandSourceStack> dispatcher, final Command<C> command) {
|
||||
|
|
@ -178,7 +242,8 @@ abstract class FabricCommandRegistrationHandler<C, S extends SharedSuggestionPro
|
|||
perm
|
||||
),
|
||||
true,
|
||||
new FabricExecutor<>(this.commandManager(), CommandSourceStack::getTextName, CommandSourceStack::sendFailure));
|
||||
new FabricExecutor<>(this.commandManager(), CommandSourceStack::getTextName, CommandSourceStack::sendFailure)
|
||||
);
|
||||
|
||||
dispatcher.addChild(baseNode);
|
||||
|
||||
|
|
@ -186,5 +251,7 @@ abstract class FabricCommandRegistrationHandler<C, S extends SharedSuggestionPro
|
|||
dispatcher.addChild(buildRedirect(alias, baseNode));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import cloud.commandframework.exceptions.NoSuchCommandException;
|
|||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
|
@ -44,16 +45,13 @@ import net.minecraft.network.chat.Component;
|
|||
import net.minecraft.network.chat.ComponentUtils;
|
||||
import net.minecraft.network.chat.HoverEvent;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
final class FabricExecutor<C, S extends SharedSuggestionProvider> implements Command<S> {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
private static final Component NEWLINE = new TextComponent("\n");
|
||||
private static final Component NEWLINE = Component.literal("\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. "
|
||||
|
|
@ -79,6 +77,7 @@ final class FabricExecutor<C, S extends SharedSuggestionProvider> implements Com
|
|||
final S source = ctx.getSource();
|
||||
final String input = ctx.getInput().substring(ctx.getLastChild().getNodes().get(0).getRange().getStart());
|
||||
final C sender = this.manager.commandSourceMapper().apply(source);
|
||||
|
||||
this.manager.executeCommand(sender, input).whenComplete((result, throwable) -> {
|
||||
if (throwable == null) {
|
||||
return;
|
||||
|
|
@ -99,8 +98,8 @@ final class FabricExecutor<C, S extends SharedSuggestionProvider> implements Com
|
|||
(InvalidSyntaxException) throwable,
|
||||
(c, e) -> this.sendError.accept(
|
||||
source,
|
||||
new TextComponent("Invalid Command Syntax. Correct command syntax is: ")
|
||||
.append(new TextComponent(String.format("/%s", e.getCorrectSyntax()))
|
||||
Component.literal("Invalid Command Syntax. Correct command syntax is: ")
|
||||
.append(Component.literal(String.format("/%s", e.getCorrectSyntax()))
|
||||
.withStyle(style -> style.withColor(ChatFormatting.GRAY)))
|
||||
)
|
||||
);
|
||||
|
|
@ -109,21 +108,21 @@ final class FabricExecutor<C, S extends SharedSuggestionProvider> implements Com
|
|||
sender,
|
||||
InvalidCommandSenderException.class,
|
||||
(InvalidCommandSenderException) throwable,
|
||||
(c, e) -> this.sendError.accept(source, new TextComponent(throwable.getMessage()))
|
||||
(c, e) -> this.sendError.accept(source, Component.literal(throwable.getMessage()))
|
||||
);
|
||||
} else if (throwable instanceof NoPermissionException) {
|
||||
this.manager.handleException(
|
||||
sender,
|
||||
NoPermissionException.class,
|
||||
(NoPermissionException) throwable,
|
||||
(c, e) -> this.sendError.accept(source, new TextComponent(MESSAGE_NO_PERMS))
|
||||
(c, e) -> this.sendError.accept(source, Component.literal(MESSAGE_NO_PERMS))
|
||||
);
|
||||
} else if (throwable instanceof NoSuchCommandException) {
|
||||
this.manager.handleException(
|
||||
sender,
|
||||
NoSuchCommandException.class,
|
||||
(NoSuchCommandException) throwable,
|
||||
(c, e) -> this.sendError.accept(source, new TextComponent(MESSAGE_UNKNOWN_COMMAND))
|
||||
(c, e) -> this.sendError.accept(source, Component.literal(MESSAGE_UNKNOWN_COMMAND))
|
||||
);
|
||||
} else if (throwable instanceof ArgumentParseException) {
|
||||
this.manager.handleException(
|
||||
|
|
@ -132,14 +131,14 @@ final class FabricExecutor<C, S extends SharedSuggestionProvider> implements Com
|
|||
(ArgumentParseException) throwable,
|
||||
(c, e) -> {
|
||||
if (throwable.getCause() instanceof CommandSyntaxException) {
|
||||
this.sendError.accept(source, new TextComponent("Invalid Command Argument: ")
|
||||
.append(new TextComponent("")
|
||||
this.sendError.accept(source, Component.literal("Invalid Command Argument: ")
|
||||
.append(Component.literal("")
|
||||
.append(ComponentUtils
|
||||
.fromMessage(((CommandSyntaxException) throwable.getCause()).getRawMessage()))
|
||||
.withStyle(ChatFormatting.GRAY)));
|
||||
} else {
|
||||
this.sendError.accept(source, new TextComponent("Invalid Command Argument: ")
|
||||
.append(new TextComponent(throwable.getCause().getMessage())
|
||||
this.sendError.accept(source, Component.literal("Invalid Command Argument: ")
|
||||
.append(Component.literal(throwable.getCause().getMessage())
|
||||
.withStyle(ChatFormatting.GRAY)));
|
||||
}
|
||||
}
|
||||
|
|
@ -151,7 +150,7 @@ final class FabricExecutor<C, S extends SharedSuggestionProvider> implements Com
|
|||
(CommandExecutionException) throwable,
|
||||
(c, e) -> {
|
||||
this.sendError.accept(source, this.decorateHoverStacktrace(
|
||||
new TextComponent(MESSAGE_INTERNAL_ERROR),
|
||||
Component.literal(MESSAGE_INTERNAL_ERROR),
|
||||
throwable.getCause(),
|
||||
sender
|
||||
));
|
||||
|
|
@ -164,7 +163,7 @@ final class FabricExecutor<C, S extends SharedSuggestionProvider> implements Com
|
|||
);
|
||||
} else {
|
||||
this.sendError.accept(source, this.decorateHoverStacktrace(
|
||||
new TextComponent(MESSAGE_INTERNAL_ERROR),
|
||||
Component.literal(MESSAGE_INTERNAL_ERROR),
|
||||
throwable,
|
||||
sender
|
||||
));
|
||||
|
|
@ -183,9 +182,9 @@ final class FabricExecutor<C, S extends SharedSuggestionProvider> implements Com
|
|||
return input.withStyle(style -> style
|
||||
.withHoverEvent(new HoverEvent(
|
||||
HoverEvent.Action.SHOW_TEXT,
|
||||
new TextComponent(stackTrace)
|
||||
Component.literal(stackTrace)
|
||||
.append(NEWLINE)
|
||||
.append(new TextComponent(" Click to copy")
|
||||
.append(Component.literal(" Click to copy")
|
||||
.withStyle(s2 -> s2.withColor(ChatFormatting.GRAY).withItalic(true)))
|
||||
))
|
||||
.withClickEvent(new ClickEvent(
|
||||
|
|
|
|||
|
|
@ -40,11 +40,11 @@ import cloud.commandframework.meta.CommandMeta;
|
|||
import io.leangen.geantyref.TypeToken;
|
||||
import java.util.function.Function;
|
||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.minecraft.commands.CommandSource;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.phys.Vec2;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
|
@ -121,7 +121,7 @@ public final class FabricServerCommandManager<C> extends FabricCommandManager<C,
|
|||
null,
|
||||
4,
|
||||
"",
|
||||
TextComponent.EMPTY,
|
||||
Component.empty(),
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import cloud.commandframework.arguments.parser.ArgumentParser;
|
|||
import cloud.commandframework.brigadier.argument.WrappedBrigadierParser;
|
||||
import cloud.commandframework.context.CommandContext;
|
||||
import cloud.commandframework.fabric.FabricCommandContextKeys;
|
||||
import cloud.commandframework.fabric.FabricCommandManager;
|
||||
import cloud.commandframework.fabric.data.Coordinates;
|
||||
import cloud.commandframework.fabric.data.Message;
|
||||
import cloud.commandframework.fabric.data.MinecraftTime;
|
||||
|
|
@ -38,11 +39,17 @@ import cloud.commandframework.fabric.data.SinglePlayerSelector;
|
|||
import cloud.commandframework.fabric.internal.EntitySelectorAccess;
|
||||
import cloud.commandframework.fabric.mixin.MessageArgumentMessageAccess;
|
||||
import cloud.commandframework.fabric.mixin.MessageArgumentPartAccess;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.commands.CommandBuildContext;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
|
|
@ -59,6 +66,7 @@ import net.minecraft.server.level.ServerPlayer;
|
|||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Parsers for Vanilla command argument types.
|
||||
|
|
@ -70,6 +78,17 @@ public final class FabricArgumentParsers {
|
|||
private FabricArgumentParsers() {
|
||||
}
|
||||
|
||||
/**
|
||||
* A parser that wraps Brigadier argument types which need a {@link CommandBuildContext}
|
||||
* @param <C> sender type
|
||||
* @param <V> argument value type
|
||||
* @param factory factory that creates these arguments
|
||||
* @return the parser
|
||||
*/
|
||||
public static <C, V> @NonNull ArgumentParser<C, V> contextual(final @NonNull Function<CommandBuildContext, ArgumentType<V>> factory) {
|
||||
return new WrappedBrigadierParser<>(new ContextualArgumentTypeProvider<>(factory));
|
||||
}
|
||||
|
||||
/**
|
||||
* A parser for in-game time, in ticks.
|
||||
*
|
||||
|
|
@ -505,4 +524,94 @@ public final class FabricArgumentParsers {
|
|||
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static final class ContextualArgumentTypeProvider<V> implements Supplier<ArgumentType<V>> {
|
||||
private static final ThreadLocal<ThreadLocalContext> CONTEXT = new ThreadLocal<>();
|
||||
private static final Map<FabricCommandManager<?, ?>, Set<ContextualArgumentTypeProvider<?>>> INSTANCES =
|
||||
new WeakHashMap<>();
|
||||
|
||||
private final Function<CommandBuildContext, ArgumentType<V>> provider;
|
||||
private volatile ArgumentType<V> provided;
|
||||
|
||||
/**
|
||||
* Temporarily expose a command build context to providers called from this thread.
|
||||
*
|
||||
* @param ctx the context
|
||||
* @param commandManager command manager to use
|
||||
* @param resetExisting whether to clear cached state from existing provider instances for this command type
|
||||
* @param action an action to perform while the context is exposed
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public static void withBuildContext(
|
||||
final FabricCommandManager<?, ?> commandManager,
|
||||
final CommandBuildContext ctx,
|
||||
final boolean resetExisting,
|
||||
final Runnable action
|
||||
) {
|
||||
final ThreadLocalContext context = new ThreadLocalContext(commandManager, ctx);
|
||||
CONTEXT.set(context);
|
||||
|
||||
try {
|
||||
if (resetExisting) {
|
||||
synchronized (INSTANCES) {
|
||||
for (final ContextualArgumentTypeProvider<?> contextualArgumentTypeProvider : context.instances()) {
|
||||
contextualArgumentTypeProvider.provided = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action.run();
|
||||
} finally {
|
||||
CONTEXT.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ThreadLocalContext {
|
||||
private final FabricCommandManager<?, ?> commandManager;
|
||||
private final CommandBuildContext commandBuildContext;
|
||||
|
||||
private ThreadLocalContext(
|
||||
final FabricCommandManager<?, ?> commandManager,
|
||||
final CommandBuildContext commandBuildContext
|
||||
) {
|
||||
this.commandManager = commandManager;
|
||||
this.commandBuildContext = commandBuildContext;
|
||||
}
|
||||
|
||||
private Set<ContextualArgumentTypeProvider<?>> instances() {
|
||||
return INSTANCES.computeIfAbsent(this.commandManager, $ -> Collections.newSetFromMap(new WeakHashMap<>()));
|
||||
}
|
||||
}
|
||||
|
||||
ContextualArgumentTypeProvider(final @NonNull Function<CommandBuildContext, ArgumentType<V>> provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentType<V> get() {
|
||||
final ThreadLocalContext ctx = CONTEXT.get();
|
||||
|
||||
if (ctx != null) {
|
||||
synchronized (INSTANCES) {
|
||||
ctx.instances().add(this);
|
||||
}
|
||||
}
|
||||
|
||||
ArgumentType<V> provided = this.provided;
|
||||
if (provided == null) {
|
||||
synchronized (this) {
|
||||
if (this.provided == null) {
|
||||
if (ctx == null) {
|
||||
throw new IllegalStateException("No build context was available while trying to compute an argument type");
|
||||
}
|
||||
provided = this.provider.apply(ctx.commandBuildContext);
|
||||
this.provided = provided;
|
||||
}
|
||||
}
|
||||
}
|
||||
return provided;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,13 +35,13 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* An argument parsing an unbounded {@link net.minecraft.advancements.critereon.MinMaxBounds.Floats float range}, in the form
|
||||
* An argument parsing an unbounded {@link net.minecraft.advancements.critereon.MinMaxBounds.Doubles double range}, in the form
|
||||
* {@code [min]..[max]}, where both lower and upper bounds are optional.
|
||||
*
|
||||
* @param <C> the sender type
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public final class FloatRangeArgument<C> extends CommandArgument<C, MinMaxBounds.Floats> {
|
||||
public final class FloatRangeArgument<C> extends CommandArgument<C, MinMaxBounds.Doubles> {
|
||||
|
||||
FloatRangeArgument(
|
||||
final boolean required,
|
||||
|
|
@ -55,7 +55,7 @@ public final class FloatRangeArgument<C> extends CommandArgument<C, MinMaxBounds
|
|||
name,
|
||||
new WrappedBrigadierParser<>(RangeArgument.floatRange()),
|
||||
defaultValue,
|
||||
MinMaxBounds.Floats.class,
|
||||
MinMaxBounds.Doubles.class,
|
||||
suggestionsProvider,
|
||||
defaultDescription
|
||||
);
|
||||
|
|
@ -108,7 +108,7 @@ public final class FloatRangeArgument<C> extends CommandArgument<C, MinMaxBounds
|
|||
*/
|
||||
public static <C> @NonNull FloatRangeArgument<C> optional(
|
||||
final @NonNull String name,
|
||||
final MinMaxBounds.@NonNull Floats defaultValue
|
||||
final MinMaxBounds.@NonNull Doubles defaultValue
|
||||
) {
|
||||
return FloatRangeArgument.<C>builder(name).asOptionalWithDefault(defaultValue).build();
|
||||
}
|
||||
|
|
@ -120,10 +120,10 @@ public final class FloatRangeArgument<C> extends CommandArgument<C, MinMaxBounds
|
|||
* @param <C> sender type
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public static final class Builder<C> extends TypedBuilder<C, MinMaxBounds.Floats, Builder<C>> {
|
||||
public static final class Builder<C> extends TypedBuilder<C, MinMaxBounds.Doubles, Builder<C>> {
|
||||
|
||||
Builder(final @NonNull String name) {
|
||||
super(MinMaxBounds.Floats.class, name);
|
||||
super(MinMaxBounds.Doubles.class, name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -151,7 +151,7 @@ public final class FloatRangeArgument<C> extends CommandArgument<C, MinMaxBounds
|
|||
* @see CommandArgument.Builder#asOptionalWithDefault(String)
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public @NonNull Builder<C> asOptionalWithDefault(final MinMaxBounds.@NonNull Floats defaultValue) {
|
||||
public @NonNull Builder<C> asOptionalWithDefault(final MinMaxBounds.@NonNull Doubles defaultValue) {
|
||||
final StringBuilder value = new StringBuilder(6);
|
||||
if (defaultValue.getMin() != null) {
|
||||
value.append(defaultValue.getMin());
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ package cloud.commandframework.fabric.argument;
|
|||
|
||||
import cloud.commandframework.ArgumentDescription;
|
||||
import cloud.commandframework.arguments.CommandArgument;
|
||||
import cloud.commandframework.brigadier.argument.WrappedBrigadierParser;
|
||||
import cloud.commandframework.context.CommandContext;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
|
@ -54,7 +53,7 @@ public final class ItemInputArgument<C> extends CommandArgument<C, ItemInput> {
|
|||
super(
|
||||
required,
|
||||
name,
|
||||
new WrappedBrigadierParser<>(ItemArgument.item()),
|
||||
FabricArgumentParsers.contextual(ItemArgument::item),
|
||||
defaultValue,
|
||||
ItemInput.class,
|
||||
suggestionsProvider,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import cloud.commandframework.arguments.parser.ArgumentParser;
|
|||
import cloud.commandframework.context.CommandContext;
|
||||
import cloud.commandframework.fabric.FabricCommandContextKeys;
|
||||
import java.util.Queue;
|
||||
import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.function.BiFunction;
|
||||
import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.world.scores.PlayerTeam;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
|
|
|||
|
|
@ -1,26 +1,3 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
/**
|
||||
* Arguments for the Fabric environment.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -25,9 +25,10 @@
|
|||
|
||||
"depends": {
|
||||
"fabricloader": ">=0.7.4",
|
||||
"fabric-command-api-v1": "*",
|
||||
"fabric-command-api-v2": "*",
|
||||
"fabric-networking-api-v1": "*",
|
||||
"fabric-lifecycle-events-v1": "*",
|
||||
"fabric-permissions-api-v0": "*",
|
||||
"minecraft": ">=1.14"
|
||||
"minecraft": ">1.18.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,29 +27,32 @@ import cloud.commandframework.Command;
|
|||
import cloud.commandframework.arguments.standard.StringArgument;
|
||||
import cloud.commandframework.execution.CommandExecutionCoordinator;
|
||||
import cloud.commandframework.fabric.FabricClientCommandManager;
|
||||
import cloud.commandframework.fabric.argument.ItemInputArgument;
|
||||
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 com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.realmsclient.RealmsMainScreen;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.GenericDirtMessageScreen;
|
||||
import net.minecraft.client.gui.screens.TitleScreen;
|
||||
import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.commands.synchronization.ArgumentTypes;
|
||||
import net.minecraft.commands.arguments.item.ItemInput;
|
||||
import net.minecraft.commands.synchronization.ArgumentUtils;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.realms.RealmsBridge;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.ComponentUtils;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public final class FabricClientExample implements ClientModInitializer {
|
||||
|
|
@ -68,8 +71,8 @@ public final class FabricClientExample implements ClientModInitializer {
|
|||
"cloud-dump-" + Instant.now().toString().replace(':', '-') + ".json"
|
||||
);
|
||||
ctx.getSender().sendFeedback(
|
||||
new TextComponent("Dumping command output to ")
|
||||
.append(new TextComponent(target.toString())
|
||||
Component.literal("Dumping command output to ")
|
||||
.append(Component.literal(target.toString())
|
||||
.withStyle(s -> s.withClickEvent(new ClickEvent(
|
||||
ClickEvent.Action.OPEN_FILE,
|
||||
target.toAbsolutePath().toString()
|
||||
|
|
@ -80,11 +83,11 @@ public final class FabricClientExample implements ClientModInitializer {
|
|||
final CommandDispatcher<SharedSuggestionProvider> dispatcher = Minecraft.getInstance()
|
||||
.getConnection()
|
||||
.getCommands();
|
||||
final JsonObject object = ArgumentTypes.serializeNodeToJson(dispatcher, dispatcher.getRoot());
|
||||
final JsonObject object = ArgumentUtils.serializeNodeToJson(dispatcher, dispatcher.getRoot());
|
||||
json.setIndent(" ");
|
||||
Streams.write(object, json);
|
||||
} catch (final IOException ex) {
|
||||
ctx.getSender().sendError(new TextComponent(
|
||||
ctx.getSender().sendError(Component.literal(
|
||||
"Unable to write file, see console for details: " + ex.getMessage()
|
||||
));
|
||||
}
|
||||
|
|
@ -93,7 +96,7 @@ public final class FabricClientExample implements ClientModInitializer {
|
|||
commandManager.command(base.literal("say")
|
||||
.argument(StringArgument.greedy("message"))
|
||||
.handler(ctx -> ctx.getSender().sendFeedback(
|
||||
new TextComponent("Cloud client commands says: " + ctx.get("message"))
|
||||
Component.literal("Cloud client commands says: " + ctx.get("message"))
|
||||
)));
|
||||
|
||||
commandManager.command(base.literal("quit")
|
||||
|
|
@ -108,21 +111,34 @@ public final class FabricClientExample implements ClientModInitializer {
|
|||
|
||||
commandManager.command(base.literal("requires_cheats")
|
||||
.permission(FabricClientCommandManager.cheatsAllowed(false))
|
||||
.handler(ctx -> ctx.getSender().sendFeedback(new TextComponent("Cheats are enabled!"))));
|
||||
.handler(ctx -> ctx.getSender().sendFeedback(Component.literal("Cheats are enabled!"))));
|
||||
|
||||
// Test argument which requires CommandBuildContext/RegistryAccess
|
||||
commandManager.command(base.literal("show_item")
|
||||
.argument(ItemInputArgument.of("item"))
|
||||
.handler(ctx -> {
|
||||
try {
|
||||
ctx.getSender().sendFeedback(
|
||||
ctx.<ItemInput>get("item").createItemStack(1, false).getDisplayName()
|
||||
);
|
||||
} catch (final CommandSyntaxException ex) {
|
||||
ctx.getSender().sendError(ComponentUtils.fromMessage(ex.getRawMessage()));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private static void disconnectClient(final @NonNull Minecraft client) {
|
||||
boolean singlePlayer = client.hasSingleplayerServer();
|
||||
final boolean singlePlayer = client.hasSingleplayerServer();
|
||||
client.level.disconnect();
|
||||
if (singlePlayer) {
|
||||
client.clearLevel(new GenericDirtMessageScreen(new TranslatableComponent("menu.savingLevel")));
|
||||
client.clearLevel(new GenericDirtMessageScreen(Component.translatable("menu.savingLevel")));
|
||||
} else {
|
||||
client.clearLevel();
|
||||
}
|
||||
if (singlePlayer) {
|
||||
client.setScreen(new TitleScreen());
|
||||
} else if (client.isConnectedToRealms()) {
|
||||
new RealmsBridge().switchToRealms(new TitleScreen());
|
||||
client.setScreen(new RealmsMainScreen(new TitleScreen()));
|
||||
} else {
|
||||
client.setScreen(new JoinMultiplayerScreen(new TitleScreen()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,16 +52,14 @@ import net.fabricmc.loader.api.ModContainer;
|
|||
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||
import net.fabricmc.loader.api.metadata.Person;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.arguments.item.ItemInput;
|
||||
import net.minecraft.network.chat.ChatType;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.ComponentUtils;
|
||||
import net.minecraft.network.chat.HoverEvent;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.TextColor;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
|
@ -86,13 +84,13 @@ public final class FabricExample implements ModInitializer {
|
|||
.argument(name)
|
||||
.argument(hugs)
|
||||
.handler(ctx -> {
|
||||
ctx.getSender().sendSuccess(new TextComponent("Hello, ")
|
||||
ctx.getSender().sendSuccess(Component.literal("Hello, ")
|
||||
.append(ctx.get(name))
|
||||
.append(", hope you're doing well!")
|
||||
.withStyle(style -> style.withColor(TextColor.fromRgb(0xAA22BB))), false);
|
||||
|
||||
ctx.getSender().sendSuccess(new TextComponent("Cloud would like to give you ")
|
||||
.append(new TextComponent(String.valueOf(ctx.get(hugs)))
|
||||
ctx.getSender().sendSuccess(Component.literal("Cloud would like to give you ")
|
||||
.append(Component.literal(String.valueOf(ctx.get(hugs)))
|
||||
.withStyle(style -> style.withColor(TextColor.fromRgb(0xFAB3DA))))
|
||||
.append(" hug(s) <3")
|
||||
.withStyle(style -> style.withBold(true)), false);
|
||||
|
|
@ -109,15 +107,13 @@ public final class FabricExample implements ModInitializer {
|
|||
final MultiplePlayerSelector selector = ctx.get(playerSelector);
|
||||
final Collection<ServerPlayer> selected = selector.get();
|
||||
selected.forEach(selectedPlayer ->
|
||||
selectedPlayer.sendMessage(
|
||||
new TextComponent("Wave from ")
|
||||
.withStyle(style -> style.withColor(ctx.get(textColor)))
|
||||
.append(ctx.getSender().getDisplayName()),
|
||||
ChatType.SYSTEM,
|
||||
Util.NIL_UUID
|
||||
selectedPlayer.sendSystemMessage(
|
||||
Component.literal("Wave from ")
|
||||
.withStyle(style -> style.withColor(ctx.get(textColor)))
|
||||
.append(ctx.getSender().getDisplayName())
|
||||
));
|
||||
ctx.getSender().sendSuccess(
|
||||
new TextComponent(String.format("Waved at %d players (%s)", selected.size(),
|
||||
Component.literal(String.format("Waved at %d players (%s)", selected.size(),
|
||||
selector.inputString()
|
||||
)),
|
||||
false
|
||||
|
|
@ -150,14 +146,14 @@ public final class FabricExample implements ModInitializer {
|
|||
.map(ModContainer::getMetadata)
|
||||
.sorted(Comparator.comparing(ModMetadata::getId))
|
||||
.collect(Collectors.toList());
|
||||
final TextComponent text = new TextComponent("");
|
||||
text.append(new TextComponent("Loaded Mods")
|
||||
final MutableComponent text = Component.literal("");
|
||||
text.append(Component.literal("Loaded Mods")
|
||||
.withStyle(style -> style.withColor(ChatFormatting.BLUE).applyFormat(ChatFormatting.BOLD)));
|
||||
text.append(new TextComponent(String.format(" (%s)\n", modList.size()))
|
||||
text.append(Component.literal(String.format(" (%s)\n", modList.size()))
|
||||
.withStyle(style -> style.withColor(ChatFormatting.GRAY).applyFormat(ChatFormatting.ITALIC)));
|
||||
for (final ModMetadata mod : modList) {
|
||||
text.append(
|
||||
new TextComponent("")
|
||||
Component.literal("")
|
||||
.withStyle(style -> style.withColor(ChatFormatting.WHITE)
|
||||
.withClickEvent(new ClickEvent(
|
||||
ClickEvent.Action.SUGGEST_COMMAND,
|
||||
|
|
@ -165,17 +161,17 @@ public final class FabricExample implements ModInitializer {
|
|||
))
|
||||
.withHoverEvent(new HoverEvent(
|
||||
HoverEvent.Action.SHOW_TEXT,
|
||||
new TextComponent("Click for more info")
|
||||
Component.literal("Click for more info")
|
||||
)))
|
||||
.append(new TextComponent(mod.getName()).withStyle(style -> style.withColor(ChatFormatting.GREEN)))
|
||||
.append(new TextComponent(String.format(" (%s) ", mod.getId()))
|
||||
.append(Component.literal(mod.getName()).withStyle(style -> style.withColor(ChatFormatting.GREEN)))
|
||||
.append(Component.literal(String.format(" (%s) ", mod.getId()))
|
||||
.withStyle(style -> style
|
||||
.withColor(ChatFormatting.GRAY)
|
||||
.applyFormat(ChatFormatting.ITALIC)))
|
||||
.append(new TextComponent(String.format("v%s", mod.getVersion())))
|
||||
.append(Component.literal(String.format("v%s", mod.getVersion())))
|
||||
);
|
||||
if (modList.indexOf(mod) != modList.size() - 1) {
|
||||
text.append(new TextComponent(", ").withStyle(style -> style.withColor(ChatFormatting.GRAY)));
|
||||
text.append(Component.literal(", ").withStyle(style -> style.withColor(ChatFormatting.GRAY)));
|
||||
}
|
||||
}
|
||||
ctx.getSender().sendSuccess(text, false);
|
||||
|
|
@ -204,23 +200,23 @@ public final class FabricExample implements ModInitializer {
|
|||
manager.command(mods.argument(modMetadata)
|
||||
.handler(ctx -> {
|
||||
final ModMetadata meta = ctx.get(modMetadata);
|
||||
final MutableComponent text = new TextComponent("")
|
||||
.append(new TextComponent(meta.getName())
|
||||
final MutableComponent text = Component.literal("")
|
||||
.append(Component.literal(meta.getName())
|
||||
.withStyle(style -> style.withColor(ChatFormatting.BLUE).applyFormat(ChatFormatting.BOLD)))
|
||||
.append(new TextComponent("\n modid: " + meta.getId()))
|
||||
.append(new TextComponent("\n version: " + meta.getVersion()))
|
||||
.append(new TextComponent("\n type: " + meta.getType()));
|
||||
.append(Component.literal("\n modid: " + meta.getId()))
|
||||
.append(Component.literal("\n version: " + meta.getVersion()))
|
||||
.append(Component.literal("\n type: " + meta.getType()));
|
||||
|
||||
if (!meta.getDescription().isEmpty()) {
|
||||
text.append(new TextComponent("\n description: " + meta.getDescription()));
|
||||
text.append(Component.literal("\n description: " + meta.getDescription()));
|
||||
}
|
||||
if (!meta.getAuthors().isEmpty()) {
|
||||
text.append(new TextComponent("\n authors: " + meta.getAuthors().stream()
|
||||
text.append(Component.literal("\n authors: " + meta.getAuthors().stream()
|
||||
.map(Person::getName)
|
||||
.collect(Collectors.joining(", "))));
|
||||
}
|
||||
if (!meta.getLicense().isEmpty()) {
|
||||
text.append(new TextComponent("\n license: " + String.join(", ", meta.getLicense())));
|
||||
text.append(Component.literal("\n license: " + String.join(", ", meta.getLicense())));
|
||||
}
|
||||
ctx.getSender().sendSuccess(
|
||||
text,
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@
|
|||
|
||||
"depends": {
|
||||
"fabricloader": ">=0.7.4",
|
||||
"fabric-command-api-v1": "*",
|
||||
"minecraft": ">=1.14",
|
||||
"fabric-command-api-v2": "*",
|
||||
"minecraft": ">1.18.2",
|
||||
"cloud": "*"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ versions:
|
|||
velocityApi: 3.1.0
|
||||
spongeApi7: 7.3.0
|
||||
jetbrainsAnnotations: 23.0.0
|
||||
fabricMinecraft: 1.16.5
|
||||
fabricLoader: 0.13.3
|
||||
fabricApi: 0.31.0+1.16
|
||||
fabricMinecraft: 1.19
|
||||
fabricLoader: 0.14.6
|
||||
fabricApi: 0.55.2+1.19
|
||||
fabricPermissionsApi: 0.1-SNAPSHOT
|
||||
|
||||
# testing
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
|||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven("https://maven.fabricmc.net")
|
||||
maven("https://maven.fabricmc.net/")
|
||||
maven("https://maven.quiltmc.org/repository/release/")
|
||||
maven("https://repo.jpenilla.xyz/snapshots/")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue