diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricServerCommandManager.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricServerCommandManager.java index 8dfaa0b1..f58d6394 100644 --- a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricServerCommandManager.java +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricServerCommandManager.java @@ -25,9 +25,13 @@ package cloud.commandframework.fabric; import cloud.commandframework.CommandTree; +import cloud.commandframework.arguments.parser.ParserParameters; import cloud.commandframework.execution.AsynchronousCommandExecutionCoordinator; import cloud.commandframework.execution.CommandExecutionCoordinator; +import cloud.commandframework.fabric.annotations.specifier.Center; import cloud.commandframework.fabric.argument.FabricArgumentParsers; +import cloud.commandframework.fabric.argument.FabricArgumentParsers.FabricParserParameters; +import cloud.commandframework.fabric.data.Coordinates; import cloud.commandframework.fabric.data.Message; import cloud.commandframework.fabric.data.MultipleEntitySelector; import cloud.commandframework.fabric.data.MultiplePlayerSelector; @@ -131,6 +135,34 @@ public final class FabricServerCommandManager extends FabricCommandManager FabricArgumentParsers.message()); + // Location arguments + this.getParserRegistry().registerAnnotationMapper( + Center.class, + (annotation, type) -> ParserParameters.single(FabricParserParameters.CENTER_INTEGERS, true) + ); + this.getParserRegistry().registerParserSupplier( + TypeToken.get(Coordinates.class), + params -> FabricArgumentParsers.vec3(params.get( + FabricParserParameters.CENTER_INTEGERS, + false + )) + ); + this.getParserRegistry().registerParserSupplier( + TypeToken.get(Coordinates.CoordinatesXZ.class), + params -> FabricArgumentParsers.vec2(params.get( + FabricParserParameters.CENTER_INTEGERS, + false + )) + ); + this.getParserRegistry().registerParserSupplier( + TypeToken.get(Coordinates.BlockCoordinates.class), + params -> FabricArgumentParsers.blockPos() + ); + this.getParserRegistry().registerParserSupplier( + TypeToken.get(Coordinates.ColumnCoordinates.class), + params -> FabricArgumentParsers.columnPos() + ); + // Entity selectors this.getParserRegistry().registerParserSupplier( TypeToken.get(SinglePlayerSelector.class), diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/annotations/package-info.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/annotations/package-info.java new file mode 100644 index 00000000..6b7ee7d5 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/annotations/package-info.java @@ -0,0 +1,30 @@ +// +// 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. +// + +/** + * Annotations for cloud-fabric. + * + * @since 1.5.0 + */ +package cloud.commandframework.fabric.annotations; diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/annotations/specifier/Center.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/annotations/specifier/Center.java new file mode 100644 index 00000000..ce699c4e --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/annotations/specifier/Center.java @@ -0,0 +1,42 @@ +// +// 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.annotations.specifier; + +import cloud.commandframework.fabric.argument.server.Vec3Argument; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation used to enable coordinate centering for {@link Vec3Argument}. + * + * @since 1.5.0 + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface Center { + +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/annotations/specifier/package-info.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/annotations/specifier/package-info.java new file mode 100644 index 00000000..9acb315b --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/annotations/specifier/package-info.java @@ -0,0 +1,30 @@ +// +// 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. +// + +/** + * Specifier annotations for cloud-fabric. + * + * @since 1.5.0 + */ +package cloud.commandframework.fabric.annotations.specifier; diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/FabricArgumentParsers.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/FabricArgumentParsers.java index 1c47f1c5..6d7239e4 100644 --- a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/FabricArgumentParsers.java +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/FabricArgumentParsers.java @@ -26,8 +26,11 @@ package cloud.commandframework.fabric.argument; import cloud.commandframework.arguments.parser.ArgumentParseResult; import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserParameter; import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; import cloud.commandframework.fabric.FabricCommandContextKeys; +import cloud.commandframework.fabric.data.Coordinates; import cloud.commandframework.fabric.data.Message; import cloud.commandframework.fabric.data.MinecraftTime; import cloud.commandframework.fabric.data.MultipleEntitySelector; @@ -38,19 +41,28 @@ import cloud.commandframework.fabric.internal.EntitySelectorAccess; import cloud.commandframework.fabric.mixin.MessageArgumentTypeMessageFormatAccess; import cloud.commandframework.fabric.mixin.MessageArgumentTypeMessageSelectorAccess; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import io.leangen.geantyref.TypeToken; import net.minecraft.command.CommandSource; import net.minecraft.command.EntitySelector; +import net.minecraft.command.argument.BlockPosArgumentType; +import net.minecraft.command.argument.ColumnPosArgumentType; import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.command.argument.MessageArgumentType; +import net.minecraft.command.argument.PosArgument; import net.minecraft.command.argument.TimeArgumentType; +import net.minecraft.command.argument.Vec2ArgumentType; +import net.minecraft.command.argument.Vec3ArgumentType; import net.minecraft.entity.Entity; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import org.checkerframework.checker.nullness.qual.NonNull; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.function.Function; /** * Parsers for Vanilla command argument types. @@ -74,6 +86,67 @@ public final class FabricArgumentParsers { .map((ctx, val) -> ArgumentParseResult.success(MinecraftTime.of(val))); } + /** + * A parser for block coordinates. + * + * @param sender type + * @return a parser instance + */ + public static @NonNull ArgumentParser blockPos() { + return new WrappedBrigadierParser(BlockPosArgumentType.blockPos()) + .map(FabricArgumentParsers::mapToCoordinates); + } + + /** + * A parser for column coordinates. + * + * @param sender type + * @return a parser instance + */ + public static @NonNull ArgumentParser columnPos() { + return new WrappedBrigadierParser(ColumnPosArgumentType.columnPos()) + .map(FabricArgumentParsers::mapToCoordinates); + } + + /** + * A parser for coordinates, relative or absolute, from 2 doubles for x and z, + * with y always defaulting to 0. + * + * @param centerIntegers whether to center integers at x.5 + * @param sender type + * @return a parser instance + */ + public static @NonNull ArgumentParser vec2(final boolean centerIntegers) { + return new WrappedBrigadierParser(new Vec2ArgumentType(centerIntegers)) + .map(FabricArgumentParsers::mapToCoordinates); + } + + /** + * A parser for coordinates, relative or absolute, from 3 doubles. + * + * @param centerIntegers whether to center integers at x.5 + * @param sender type + * @return a parser instance + */ + public static @NonNull ArgumentParser vec3(final boolean centerIntegers) { + return new WrappedBrigadierParser(Vec3ArgumentType.vec3(centerIntegers)) + .map(FabricArgumentParsers::mapToCoordinates); + } + + @SuppressWarnings("unchecked") + private static @NonNull ArgumentParseResult<@NonNull O> mapToCoordinates( + final @NonNull CommandContext ctx, + final @NonNull PosArgument posArgument + ) { + return requireServerCommandSource( + ctx, + serverCommandSource -> ArgumentParseResult.success((O) new CoordinatesImpl( + serverCommandSource, + posArgument + )) + ); + } + /** * A parser for {@link SinglePlayerSelector}. * @@ -83,21 +156,16 @@ public final class FabricArgumentParsers { */ public static @NonNull ArgumentParser singlePlayerSelector() { return new WrappedBrigadierParser(EntityArgumentType.player()) - .map((ctx, entitySelector) -> { - final CommandSource either = ctx.get(FabricCommandContextKeys.NATIVE_COMMAND_SOURCE); - if (!(either instanceof ServerCommandSource)) { - return ArgumentParseResult.failure(serverOnly()); - } - try { - return ArgumentParseResult.success(new SinglePlayerSelector( - ((EntitySelectorAccess) entitySelector).inputString(), - entitySelector, - entitySelector.getPlayer((ServerCommandSource) either) - )); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - }); + .map((ctx, entitySelector) -> requireServerCommandSource( + ctx, + serverCommandSource -> handleCommandSyntaxExceptionAsFailure( + () -> ArgumentParseResult.success(new SinglePlayerSelector( + ((EntitySelectorAccess) entitySelector).inputString(), + entitySelector, + entitySelector.getPlayer(serverCommandSource) + )) + ) + )); } /** @@ -109,21 +177,16 @@ public final class FabricArgumentParsers { */ public static @NonNull ArgumentParser multiplePlayerSelector() { return new WrappedBrigadierParser(EntityArgumentType.players()) - .map((ctx, entitySelector) -> { - final CommandSource either = ctx.get(FabricCommandContextKeys.NATIVE_COMMAND_SOURCE); - if (!(either instanceof ServerCommandSource)) { - return ArgumentParseResult.failure(serverOnly()); - } - try { - return ArgumentParseResult.success(new MultiplePlayerSelector( - ((EntitySelectorAccess) entitySelector).inputString(), - entitySelector, - entitySelector.getPlayers((ServerCommandSource) either) - )); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - }); + .map((ctx, entitySelector) -> requireServerCommandSource( + ctx, + serverCommandSource -> handleCommandSyntaxExceptionAsFailure( + () -> ArgumentParseResult.success(new MultiplePlayerSelector( + ((EntitySelectorAccess) entitySelector).inputString(), + entitySelector, + entitySelector.getPlayers(serverCommandSource) + )) + ) + )); } /** @@ -135,21 +198,16 @@ public final class FabricArgumentParsers { */ public static @NonNull ArgumentParser singleEntitySelector() { return new WrappedBrigadierParser(EntityArgumentType.entity()) - .map((ctx, entitySelector) -> { - final CommandSource either = ctx.get(FabricCommandContextKeys.NATIVE_COMMAND_SOURCE); - if (!(either instanceof ServerCommandSource)) { - return ArgumentParseResult.failure(serverOnly()); - } - try { - return ArgumentParseResult.success(new SingleEntitySelector( - ((EntitySelectorAccess) entitySelector).inputString(), - entitySelector, - entitySelector.getEntity((ServerCommandSource) either) - )); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - }); + .map((ctx, entitySelector) -> requireServerCommandSource( + ctx, + serverCommandSource -> handleCommandSyntaxExceptionAsFailure( + () -> ArgumentParseResult.success(new SingleEntitySelector( + ((EntitySelectorAccess) entitySelector).inputString(), + entitySelector, + entitySelector.getEntity(serverCommandSource) + )) + ) + )); } /** @@ -161,21 +219,16 @@ public final class FabricArgumentParsers { */ public static @NonNull ArgumentParser multipleEntitySelector() { return new WrappedBrigadierParser(EntityArgumentType.entities()) - .map((ctx, entitySelector) -> { - final CommandSource either = ctx.get(FabricCommandContextKeys.NATIVE_COMMAND_SOURCE); - if (!(either instanceof ServerCommandSource)) { - return ArgumentParseResult.failure(serverOnly()); - } - try { - return ArgumentParseResult.success(new MultipleEntitySelector( - ((EntitySelectorAccess) entitySelector).inputString(), - entitySelector, - Collections.unmodifiableCollection(entitySelector.getEntities((ServerCommandSource) either)) - )); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - }); + .map((ctx, entitySelector) -> requireServerCommandSource( + ctx, + serverCommandSource -> handleCommandSyntaxExceptionAsFailure( + () -> ArgumentParseResult.success(new MultipleEntitySelector( + ((EntitySelectorAccess) entitySelector).inputString(), + entitySelector, + Collections.unmodifiableCollection(entitySelector.getEntities(serverCommandSource)) + )) + ) + )); } /** @@ -187,28 +240,75 @@ public final class FabricArgumentParsers { */ public static @NonNull ArgumentParser message() { return new WrappedBrigadierParser(MessageArgumentType.message()) - .map((ctx, format) -> { - final CommandSource either = ctx.get(FabricCommandContextKeys.NATIVE_COMMAND_SOURCE); - if (!(either instanceof ServerCommandSource)) { - return ArgumentParseResult.failure(serverOnly()); - } - try { - return ArgumentParseResult.success(MessageImpl.from( - (ServerCommandSource) either, - format, - true - )); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - }); + .map((ctx, format) -> requireServerCommandSource( + ctx, + serverCommandSource -> handleCommandSyntaxExceptionAsFailure( + () -> ArgumentParseResult.success(MessageImpl.from( + serverCommandSource, + format, + true + )) + ) + )); + } + + @FunctionalInterface + private interface CommandSyntaxExceptionThrowingParseResultSupplier { + + @NonNull ArgumentParseResult result() throws CommandSyntaxException; + + } + + private static @NonNull ArgumentParseResult handleCommandSyntaxExceptionAsFailure( + final @NonNull CommandSyntaxExceptionThrowingParseResultSupplier resultSupplier + ) { + try { + return resultSupplier.result(); + } catch (final CommandSyntaxException ex) { + return ArgumentParseResult.failure(ex); + } } private static @NonNull IllegalStateException serverOnly() { return new IllegalStateException("This command argument type is server-only."); } + private static @NonNull ArgumentParseResult requireServerCommandSource( + final @NonNull CommandContext context, + final @NonNull Function> resultFunction + ) { + final CommandSource nativeSource = context.get(FabricCommandContextKeys.NATIVE_COMMAND_SOURCE); + if (!(nativeSource instanceof ServerCommandSource)) { + return ArgumentParseResult.failure(serverOnly()); + } + return resultFunction.apply((ServerCommandSource) nativeSource); + } + + /** + * {@link ParserParameter} keys for cloud-fabric. + * + * @since 1.5.0 + */ + public static final class FabricParserParameters { + + /** + * Indicates that positions should be centered on the middle of blocks, i.e. x.5. + * + * @since 1.5.0 + */ + public static final ParserParameter CENTER_INTEGERS = create("center_integers", TypeToken.get(Boolean.class)); + + private static @NonNull ParserParameter create( + final @NonNull String key, + final @NonNull TypeToken expectedType + ) { + return new ParserParameter<>(key, expectedType); + } + + } + static final class MessageImpl implements Message { + private final Collection mentionedEntities; private final Text contents; @@ -217,7 +317,7 @@ public final class FabricArgumentParsers { final MessageArgumentType.@NonNull MessageFormat message, final boolean useSelectors ) throws CommandSyntaxException { - final Text contents = message.format(source, useSelectors); + final Text contents = message.format(source, useSelectors); final MessageArgumentType.MessageSelector[] selectors = ((MessageArgumentTypeMessageFormatAccess) message).accessor$selectors(); final Collection entities; @@ -226,7 +326,9 @@ public final class FabricArgumentParsers { } else { entities = new HashSet<>(); for (final MessageArgumentType.MessageSelector selector : selectors) { - entities.addAll(((MessageArgumentTypeMessageSelectorAccess) selector).accessor$selector().getEntities(source)); + entities.addAll(((MessageArgumentTypeMessageSelectorAccess) selector) + .accessor$selector() + .getEntities(source)); } } @@ -250,4 +352,49 @@ public final class FabricArgumentParsers { } + static final class CoordinatesImpl implements Coordinates, + Coordinates.CoordinatesXZ, + Coordinates.BlockCoordinates, + Coordinates.ColumnCoordinates { + + private final ServerCommandSource source; + private final PosArgument posArgument; + + private CoordinatesImpl(final @NonNull ServerCommandSource source, final @NonNull PosArgument posArgument) { + this.source = source; + this.posArgument = posArgument; + } + + @Override + public @NonNull Vec3d position() { + return this.posArgument.toAbsolutePos(this.source); + } + + @Override + public @NonNull BlockPos blockPos() { + return new BlockPos(this.position()); + } + + @Override + public boolean isXRelative() { + return this.posArgument.isXRelative(); + } + + @Override + public boolean isYRelative() { + return this.posArgument.isYRelative(); + } + + @Override + public boolean isZRelative() { + return this.posArgument.isZRelative(); + } + + @Override + public @NonNull PosArgument getWrappedCoordinates() { + return this.posArgument; + } + + } + } diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/BlockPosArgument.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/BlockPosArgument.java new file mode 100644 index 00000000..ac4238c4 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/BlockPosArgument.java @@ -0,0 +1,151 @@ +// +// 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.argument.server; + +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.fabric.argument.FabricArgumentParsers; +import cloud.commandframework.fabric.data.Coordinates.BlockCoordinates; +import net.minecraft.util.math.BlockPos; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.List; +import java.util.function.BiFunction; + +/** + * An argument for resolving block coordinates. + * + * @param the sender type + * @since 1.5.0 + */ +public final class BlockPosArgument extends CommandArgument { + + BlockPosArgument( + final boolean required, + final @NonNull String name, + final @NonNull String defaultValue, + final @Nullable BiFunction, String, List> suggestionsProvider + ) { + super( + required, + name, + FabricArgumentParsers.blockPos(), + defaultValue, + BlockCoordinates.class, + suggestionsProvider + ); + } + + /** + * Create a new builder. + * + * @param name Name of the argument + * @param Command sender type + * @return Created builder + * @since 1.5.0 + */ + public static BlockPosArgument.@NonNull Builder newBuilder(final @NonNull String name) { + return new BlockPosArgument.Builder<>(name); + } + + /** + * Create a new required command argument. + * + * @param name Component name + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull BlockPosArgument of(final @NonNull String name) { + return BlockPosArgument.newBuilder(name).asRequired().build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull BlockPosArgument optional(final @NonNull String name) { + return BlockPosArgument.newBuilder(name).asOptional().build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param defaultValue default value + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull BlockPosArgument optional(final @NonNull String name, final @NonNull BlockPos defaultValue) { + return BlockPosArgument.newBuilder(name) + .asOptionalWithDefault(serializeBlockPos(defaultValue)) + .build(); + } + + private static @NonNull String serializeBlockPos(final @NonNull BlockPos pos) { + return String.format( + "%s %s %s", + pos.getX(), + pos.getY(), + pos.getZ() + ); + } + + /** + * Builder for {@link BlockPosArgument}. + * + * @param sender type + * @since 1.5.0 + */ + public static final class Builder extends TypedBuilder> { + + Builder(final @NonNull String name) { + super(BlockCoordinates.class, name); + } + + /** + * Build a block position argument. + * + * @return Constructed argument + * @since 1.5.0 + */ + @Override + public @NonNull BlockPosArgument build() { + return new BlockPosArgument<>( + this.isRequired(), + this.getName(), + this.getDefaultValue(), + this.getSuggestionsProvider() + ); + } + + } + +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/ColumnPosArgument.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/ColumnPosArgument.java new file mode 100644 index 00000000..9a2c53b3 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/ColumnPosArgument.java @@ -0,0 +1,150 @@ +// +// 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.argument.server; + +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.fabric.argument.FabricArgumentParsers; +import cloud.commandframework.fabric.data.Coordinates.ColumnCoordinates; +import net.minecraft.util.math.BlockPos; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.List; +import java.util.function.BiFunction; + +/** + * An argument for resolving column (xz) coordinates. + * + * @param the sender type + * @since 1.5.0 + */ +public final class ColumnPosArgument extends CommandArgument { + + ColumnPosArgument( + final boolean required, + final @NonNull String name, + final @NonNull String defaultValue, + final @Nullable BiFunction, String, List> suggestionsProvider + ) { + super( + required, + name, + FabricArgumentParsers.columnPos(), + defaultValue, + ColumnCoordinates.class, + suggestionsProvider + ); + } + + /** + * Create a new builder. + * + * @param name Name of the argument + * @param Command sender type + * @return Created builder + * @since 1.5.0 + */ + public static ColumnPosArgument.@NonNull Builder newBuilder(final @NonNull String name) { + return new ColumnPosArgument.Builder<>(name); + } + + /** + * Create a new required command argument. + * + * @param name Component name + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull ColumnPosArgument of(final @NonNull String name) { + return ColumnPosArgument.newBuilder(name).asRequired().build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull ColumnPosArgument optional(final @NonNull String name) { + return ColumnPosArgument.newBuilder(name).asOptional().build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param defaultValue default value, y coordinate will be ignored as it is always 0 + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull ColumnPosArgument optional(final @NonNull String name, final @NonNull BlockPos defaultValue) { + return ColumnPosArgument.newBuilder(name) + .asOptionalWithDefault(serializeColumnPos(defaultValue)) + .build(); + } + + private static @NonNull String serializeColumnPos(final @NonNull BlockPos pos) { + return String.format( + "%s %s", + pos.getX(), + pos.getZ() + ); + } + + /** + * Builder for {@link ColumnPosArgument}. + * + * @param sender type + * @since 1.5.0 + */ + public static final class Builder extends TypedBuilder> { + + Builder(final @NonNull String name) { + super(ColumnCoordinates.class, name); + } + + /** + * Build a column position argument. + * + * @return Constructed argument + * @since 1.5.0 + */ + @Override + public @NonNull ColumnPosArgument build() { + return new ColumnPosArgument<>( + this.isRequired(), + this.getName(), + this.getDefaultValue(), + this.getSuggestionsProvider() + ); + } + + } + +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/Vec2Argument.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/Vec2Argument.java new file mode 100644 index 00000000..2c67d95e --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/Vec2Argument.java @@ -0,0 +1,236 @@ +// +// 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.argument.server; + +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.fabric.argument.FabricArgumentParsers; +import cloud.commandframework.fabric.data.Coordinates; +import net.minecraft.util.math.Vec3d; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.List; +import java.util.function.BiFunction; + +/** + * An argument for resolving x and z coordinates from 2 doubles. + * + * @param the sender type + * @since 1.5.0 + */ +public final class Vec2Argument extends CommandArgument { + + private final boolean centerIntegers; + + Vec2Argument( + final boolean required, + final @NonNull String name, + final @NonNull String defaultValue, + final @Nullable BiFunction, String, List> suggestionsProvider, + final boolean centerIntegers + ) { + super( + required, + name, + FabricArgumentParsers.vec2(centerIntegers), + defaultValue, + Coordinates.CoordinatesXZ.class, + suggestionsProvider + ); + this.centerIntegers = centerIntegers; + } + + /** + * Get whether integers will be centered to x.5. Defaults to false. + * + * @return whether integers will be centered + * @since 1.5.0 + */ + public boolean centerIntegers() { + return this.centerIntegers; + } + + /** + * Create a new builder. + * + * @param name Name of the argument + * @param Command sender type + * @return Created builder + * @since 1.5.0 + */ + public static Vec2Argument.@NonNull Builder newBuilder(final @NonNull String name) { + return new Vec2Argument.Builder<>(name); + } + + /** + * Create a new required command argument. + * + * @param name Component name + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec2Argument of(final @NonNull String name) { + return Vec2Argument.newBuilder(name).asRequired().build(); + } + + /** + * Create a new required command argument. + * + * @param name Component name + * @param centerIntegers whether to center integers to x.5. + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec2Argument of(final @NonNull String name, final boolean centerIntegers) { + return Vec2Argument.newBuilder(name).centerIntegers(centerIntegers).asRequired().build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec2Argument optional(final @NonNull String name) { + return Vec2Argument.newBuilder(name).asOptional().build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param centerIntegers whether to center integers to x.5. + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec2Argument optional(final @NonNull String name, final boolean centerIntegers) { + return Vec2Argument.newBuilder(name).centerIntegers(centerIntegers).asOptional().build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param defaultValue default value, y will be ignored as it is always 0 + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec2Argument optional(final @NonNull String name, final @NonNull Vec3d defaultValue) { + return Vec2Argument.newBuilder(name) + .asOptionalWithDefault(serializeXandZ(defaultValue)) + .build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param defaultValue default value, y will be ignored as it is always 0 + * @param centerIntegers whether to center integers to x.5. + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec2Argument optional( + final @NonNull String name, + final boolean centerIntegers, + final @NonNull Vec3d defaultValue + ) { + return Vec2Argument.newBuilder(name) + .centerIntegers(centerIntegers) + .asOptionalWithDefault(serializeXandZ(defaultValue)) + .build(); + } + + private static @NonNull String serializeXandZ(final @NonNull Vec3d vec3d) { + return String.format( + "%.10f %.10f", + vec3d.x, + vec3d.z + ); + } + + /** + * Builder for {@link Vec2Argument}. + * + * @param sender type + * @since 1.5.0 + */ + public static final class Builder extends TypedBuilder> { + + private boolean centerIntegers = false; + + Builder(final @NonNull String name) { + super(Coordinates.CoordinatesXZ.class, name); + } + + /** + * Set whether integers will be centered to x.5. Will be false by default if unset. + * + * @param centerIntegers whether integers will be centered + * @return this builder + * @since 1.5.0 + */ + public @NonNull Builder centerIntegers(final boolean centerIntegers) { + this.centerIntegers = centerIntegers; + return this; + } + + /** + * Get whether integers will be centered to x.5. Defaults to false. + * + * @return whether integers will be centered + * @since 1.5.0 + */ + public boolean centerIntegers() { + return this.centerIntegers; + } + + /** + * Build a vec2 argument. + * + * @return Constructed argument + * @since 1.5.0 + */ + @Override + public @NonNull Vec2Argument build() { + return new Vec2Argument<>( + this.isRequired(), + this.getName(), + this.getDefaultValue(), + this.getSuggestionsProvider(), + this.centerIntegers() + ); + } + + } + +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/Vec3Argument.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/Vec3Argument.java new file mode 100644 index 00000000..4a213452 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/Vec3Argument.java @@ -0,0 +1,237 @@ +// +// 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.argument.server; + +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.fabric.argument.FabricArgumentParsers; +import cloud.commandframework.fabric.data.Coordinates; +import net.minecraft.util.math.Vec3d; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.List; +import java.util.function.BiFunction; + +/** + * An argument for resolving coordinates from 3 doubles. + * + * @param the sender type + * @since 1.5.0 + */ +public final class Vec3Argument extends CommandArgument { + + private final boolean centerIntegers; + + Vec3Argument( + final boolean required, + final @NonNull String name, + final @NonNull String defaultValue, + final @Nullable BiFunction, String, List> suggestionsProvider, + final boolean centerIntegers + ) { + super( + required, + name, + FabricArgumentParsers.vec3(centerIntegers), + defaultValue, + Coordinates.class, + suggestionsProvider + ); + this.centerIntegers = centerIntegers; + } + + /** + * Get whether integers will be centered to x.5. Defaults to false. + * + * @return whether integers will be centered + * @since 1.5.0 + */ + public boolean centerIntegers() { + return this.centerIntegers; + } + + /** + * Create a new builder. + * + * @param name Name of the argument + * @param Command sender type + * @return Created builder + * @since 1.5.0 + */ + public static Vec3Argument.@NonNull Builder newBuilder(final @NonNull String name) { + return new Vec3Argument.Builder<>(name); + } + + /** + * Create a new required command argument. + * + * @param name Component name + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec3Argument of(final @NonNull String name) { + return Vec3Argument.newBuilder(name).asRequired().build(); + } + + /** + * Create a new required command argument. + * + * @param name Component name + * @param centerIntegers whether to center integers to x.5. + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec3Argument of(final @NonNull String name, final boolean centerIntegers) { + return Vec3Argument.newBuilder(name).centerIntegers(centerIntegers).asRequired().build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec3Argument optional(final @NonNull String name) { + return Vec3Argument.newBuilder(name).asOptional().build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param centerIntegers whether to center integers to x.5. + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec3Argument optional(final @NonNull String name, final boolean centerIntegers) { + return Vec3Argument.newBuilder(name).centerIntegers(centerIntegers).asOptional().build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param defaultValue default value + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec3Argument optional(final @NonNull String name, final @NonNull Vec3d defaultValue) { + return Vec3Argument.newBuilder(name) + .asOptionalWithDefault(serializeVec3(defaultValue)) + .build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param defaultValue default value + * @param centerIntegers whether to center integers to x.5. + * @param Command sender type + * @return Created argument + * @since 1.5.0 + */ + public static @NonNull Vec3Argument optional( + final @NonNull String name, + final boolean centerIntegers, + final @NonNull Vec3d defaultValue + ) { + return Vec3Argument.newBuilder(name) + .centerIntegers(centerIntegers) + .asOptionalWithDefault(serializeVec3(defaultValue)) + .build(); + } + + private static @NonNull String serializeVec3(final @NonNull Vec3d vec3d) { + return String.format( + "%.10f %.10f %.10f", + vec3d.x, + vec3d.y, + vec3d.z + ); + } + + /** + * Builder for {@link Vec3Argument}. + * + * @param sender type + * @since 1.5.0 + */ + public static final class Builder extends TypedBuilder> { + + private boolean centerIntegers = false; + + Builder(final @NonNull String name) { + super(Coordinates.class, name); + } + + /** + * Set whether integers will be centered to x.5. Will be false by default if unset. + * + * @param centerIntegers whether integers will be centered + * @return this builder + * @since 1.5.0 + */ + public @NonNull Builder centerIntegers(final boolean centerIntegers) { + this.centerIntegers = centerIntegers; + return this; + } + + /** + * Get whether integers will be centered to x.5. Defaults to false. + * + * @return whether integers will be centered + * @since 1.5.0 + */ + public boolean centerIntegers() { + return this.centerIntegers; + } + + /** + * Build a vec3 argument. + * + * @return Constructed argument + * @since 1.5.0 + */ + @Override + public @NonNull Vec3Argument build() { + return new Vec3Argument<>( + this.isRequired(), + this.getName(), + this.getDefaultValue(), + this.getSuggestionsProvider(), + this.centerIntegers() + ); + } + + } + +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/Coordinates.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/Coordinates.java new file mode 100644 index 00000000..b112389d --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/Coordinates.java @@ -0,0 +1,117 @@ +// +// 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.data; + +import net.minecraft.command.argument.BlockPosArgumentType; +import net.minecraft.command.argument.ColumnPosArgumentType; +import net.minecraft.command.argument.PosArgument; +import net.minecraft.command.argument.Vec2ArgumentType; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * A {@link PosArgument} wrapper for easier use with cloud commands. + * + * @since 1.5.0 + */ +public interface Coordinates { + + /** + * Resolve a position from the parsed coordinates. + * + * @return position + * @since 1.5.0 + */ + @NonNull Vec3d position(); + + /** + * Resolve a block position from the parsed coordinates. + * + * @return block position + * @since 1.5.0 + */ + @NonNull BlockPos blockPos(); + + /** + * Get whether the x coordinate is relative. + * + * @return whether the x coordinate is relative + * @since 1.5.0 + */ + boolean isXRelative(); + + /** + * Get whether the y coordinate is relative. + * + * @return whether the y coordinate is relative + * @since 1.5.0 + */ + boolean isYRelative(); + + /** + * Get whether the z coordinate is relative. + * + * @return whether the z coordinate is relative + * @since 1.5.0 + */ + boolean isZRelative(); + + /** + * Get the coordinates wrapped by this {@link Coordinates}. + * + * @return the base coordinates + * @since 1.5.0 + */ + @NonNull PosArgument getWrappedCoordinates(); + + /** + * A specialized version of {@link Coordinates} for representing the result of the vanilla {@link Vec2ArgumentType}, + * which accepts two doubles for the x and z coordinate, always defaulting to 0 for the y coordinate. + * + * @since 1.5.0 + */ + interface CoordinatesXZ extends Coordinates { + + } + + /** + * A specialized version of {@link Coordinates} for representing the result of the vanilla {@link BlockPosArgumentType}. + * + * @since 1.5.0 + */ + interface BlockCoordinates extends Coordinates { + + } + + /** + * A specialized version of {@link Coordinates} for representing the result of the vanilla {@link ColumnPosArgumentType}. + * + * @since 1.5.0 + */ + interface ColumnCoordinates extends Coordinates { + + } + +} 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 index 83917195..53c82280 100644 --- 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 @@ -33,9 +33,16 @@ 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.ColumnPosArgument; +import cloud.commandframework.fabric.argument.server.MultipleEntitySelectorArgument; import cloud.commandframework.fabric.argument.server.MultiplePlayerSelectorArgument; +import cloud.commandframework.fabric.argument.server.Vec3Argument; +import cloud.commandframework.fabric.data.Coordinates; +import cloud.commandframework.fabric.data.Coordinates.ColumnCoordinates; +import cloud.commandframework.fabric.data.MultipleEntitySelector; import cloud.commandframework.fabric.data.MultiplePlayerSelector; import cloud.commandframework.fabric.testmod.mixin.GiveCommandAccess; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; @@ -52,6 +59,8 @@ import net.minecraft.text.MutableText; import net.minecraft.text.TextColor; import net.minecraft.util.Formatting; import net.minecraft.util.Util; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.Vec3d; import java.util.Collection; import java.util.Comparator; @@ -217,6 +226,33 @@ public final class FabricExample implements ModInitializer { false ); })); + + manager.command(base.literal("teleport") + .permission("cloud.teleport") + .argument(MultipleEntitySelectorArgument.of("targets")) + .argument(Vec3Argument.of("location")) + .handler(ctx -> { + final MultipleEntitySelector selector = ctx.get("targets"); + final Vec3d location = ctx.get("location").position(); + selector.get().forEach(target -> + target.requestTeleport(location.getX(), location.getY(), location.getZ())); + })); + + manager.command(base.literal("gotochunk") + .permission("cloud.gotochunk") + .argument(ColumnPosArgument.of("chunk_position")) + .handler(ctx -> { + final ServerPlayerEntity player; + try { + player = ctx.getSender().getPlayer(); + } catch (final CommandSyntaxException e) { + ctx.getSender().sendFeedback(new LiteralText("Must be a player to use this command"), false); + return; + } + final Vec3d vec = ctx.get("chunk_position").position(); + final ChunkPos pos = new ChunkPos((int) vec.getX(), (int) vec.getZ()); + player.requestTeleport(pos.getStartX(), 128, pos.getStartZ()); + })); } }