Add entity selector arguments (@p, @e, @r, etc.) for Bukkit and register with the PaperBrigadierListener.

This commit is contained in:
jmp 2020-10-02 10:02:15 -07:00 committed by Alexander Söderberg
parent b94075833d
commit 9a35a873c0
16 changed files with 1123 additions and 14 deletions

View file

@ -1,6 +1,6 @@
dependencies {
api project(':cloud-core')
api project(':cloud-brigadier')
compileOnly 'org.bukkit:bukkit:1.8.8-R0.1-SNAPSHOT'
compileOnly 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT'
compileOnly 'me.lucko:commodore:1.9'
}

View file

@ -25,10 +25,18 @@ package cloud.commandframework.bukkit;
import cloud.commandframework.CommandManager;
import cloud.commandframework.CommandTree;
import cloud.commandframework.bukkit.arguments.selector.MultipleEntitySelector;
import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector;
import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector;
import cloud.commandframework.bukkit.arguments.selector.SinglePlayerSelector;
import cloud.commandframework.bukkit.parsers.MaterialArgument;
import cloud.commandframework.bukkit.parsers.OfflinePlayerArgument;
import cloud.commandframework.bukkit.parsers.PlayerArgument;
import cloud.commandframework.bukkit.parsers.WorldArgument;
import cloud.commandframework.bukkit.parsers.selector.MultipleEntitySelectorArgument;
import cloud.commandframework.bukkit.parsers.selector.MultiplePlayerSelectorArgument;
import cloud.commandframework.bukkit.parsers.selector.SingleEntitySelectorArgument;
import cloud.commandframework.bukkit.parsers.selector.SinglePlayerSelectorArgument;
import cloud.commandframework.execution.CommandExecutionCoordinator;
import io.leangen.geantyref.TypeToken;
import org.bukkit.Bukkit;
@ -87,16 +95,6 @@ public class BukkitCommandManager<C> extends CommandManager<C> {
this.commandSenderMapper = commandSenderMapper;
this.backwardsCommandSenderMapper = backwardsCommandSenderMapper;
/* Register Bukkit parsers */
this.getParserRegistry().registerParserSupplier(TypeToken.get(World.class), params -> new WorldArgument.WorldParser<>());
this.getParserRegistry().registerParserSupplier(TypeToken.get(Material.class),
params -> new MaterialArgument.MaterialParser<>());
this.getParserRegistry()
.registerParserSupplier(TypeToken.get(Player.class), params -> new PlayerArgument.PlayerParser<>());
this.getParserRegistry()
.registerParserSupplier(TypeToken.get(OfflinePlayer.class),
params -> new OfflinePlayerArgument.OfflinePlayerParser<>());
/* Try to determine the Minecraft version */
int version = -1;
try {
@ -119,6 +117,28 @@ public class BukkitCommandManager<C> extends CommandManager<C> {
} catch (final Exception ignored) {
}
this.paper = paper;
/* Register Bukkit Preprocessor */
this.registerCommandPreProcessor(new BukkitCommandPreprocessor<>(this));
/* Register Bukkit Parsers */
this.getParserRegistry().registerParserSupplier(TypeToken.get(World.class), params -> new WorldArgument.WorldParser<>());
this.getParserRegistry().registerParserSupplier(TypeToken.get(Material.class),
params -> new MaterialArgument.MaterialParser<>());
this.getParserRegistry()
.registerParserSupplier(TypeToken.get(Player.class), params -> new PlayerArgument.PlayerParser<>());
this.getParserRegistry()
.registerParserSupplier(TypeToken.get(OfflinePlayer.class),
params -> new OfflinePlayerArgument.OfflinePlayerParser<>());
/* Register Entity Selector Parsers */
this.getParserRegistry().registerParserSupplier(TypeToken.get(SingleEntitySelector.class), parserParameters ->
new SingleEntitySelectorArgument.SingleEntitySelectorParser<>());
this.getParserRegistry().registerParserSupplier(TypeToken.get(SinglePlayerSelector.class), parserParameters ->
new SinglePlayerSelectorArgument.SinglePlayerSelectorParser<>());
this.getParserRegistry().registerParserSupplier(TypeToken.get(MultipleEntitySelector.class), parserParameters ->
new MultipleEntitySelectorArgument.MultipleEntitySelectorParser<>());
this.getParserRegistry().registerParserSupplier(TypeToken.get(MultiplePlayerSelector.class), parserParameters ->
new MultiplePlayerSelectorArgument.MultiplePlayerSelectorParser<>());
}
/**

View file

@ -0,0 +1,52 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.bukkit;
import cloud.commandframework.execution.preprocessor.CommandPreprocessingContext;
import cloud.commandframework.execution.preprocessor.CommandPreprocessor;
import org.checkerframework.checker.nullness.qual.NonNull;
public class BukkitCommandPreprocessor<C> implements CommandPreprocessor<C> {
private final BukkitCommandManager<C> mgr;
/**
* The Bukkit Command Preprocessor for storing Bukkit-specific contexts in the command contexts
*
* @param mgr The BukkitCommandManager
*/
public BukkitCommandPreprocessor(final BukkitCommandManager<C> mgr) {
this.mgr = mgr;
}
/**
* Stores the sender mapped to {@link org.bukkit.command.CommandSender} in the context with the key "BukkitCommandSender",
* and a {@link java.util.Set} of {@link CloudBukkitCapabilities} with the key "CloudBukkitCapabilities"
*/
@Override
public void accept(@NonNull final CommandPreprocessingContext<C> context) {
context.getCommandContext().store("BukkitCommandSender", mgr.getBackwardsCommandSenderMapper().apply(
context.getCommandContext().getSender()));
context.getCommandContext().store("CloudBukkitCapabilities", mgr.queryCapabilities());
}
}

View file

@ -0,0 +1,49 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.bukkit.arguments.selector;
import org.bukkit.entity.Entity;
import java.util.List;
/**
* A class to represent the result of parsing a Minecraft Entity/Target Selector argument
*/
public abstract class EntitySelector {
private final List<Entity> entities;
/**
* @param entities The List of Bukkit {@link Entity}s to construct the {@link EntitySelector} from
*/
public EntitySelector(final List<Entity> entities) {
this.entities = entities;
}
/**
* @return The list of Entities resulting from parsing the entity selector
*/
public final List<Entity> getEntities() {
return entities;
}
}

View file

@ -0,0 +1,37 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.bukkit.arguments.selector;
import org.bukkit.entity.Entity;
import java.util.List;
public class MultipleEntitySelector extends EntitySelector {
/**
* @param entities The List of Bukkit {@link Entity}s to construct the {@link EntitySelector} from
*/
public MultipleEntitySelector(final List<Entity> entities) {
super(entities);
}
}

View file

@ -0,0 +1,56 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.bukkit.arguments.selector;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class MultiplePlayerSelector extends MultipleEntitySelector {
private final List<Player> players = new ArrayList<>();
/**
* @param entities The List of Bukkit {@link Entity}s to construct the {@link EntitySelector} from
*/
public MultiplePlayerSelector(final List<Entity> entities) {
super(entities);
entities.forEach(e -> {
if (e.getType() != EntityType.PLAYER) {
throw new IllegalArgumentException("Non-players selected in player selector.");
} else {
players.add((Player) e);
}
});
}
/**
* @return The list of Bukkit Players parsed from the selector
*/
public final List<Player> getPlayers() {
return players;
}
}

View file

@ -0,0 +1,47 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.bukkit.arguments.selector;
import org.bukkit.entity.Entity;
import java.util.List;
public final class SingleEntitySelector extends MultipleEntitySelector {
/**
* @param entities The List of Bukkit {@link Entity}s to construct the {@link EntitySelector} from
*/
public SingleEntitySelector(final List<Entity> entities) {
super(entities);
if (entities.size() > 1) {
throw new IllegalArgumentException("More than 1 entity selected in single entity selector.");
}
}
/**
* @return Gets the single Bukkit Entity parsed by the selector
*/
public Entity getEntity() {
return this.getEntities().get(0);
}
}

View file

@ -0,0 +1,48 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.bukkit.arguments.selector;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import java.util.List;
public final class SinglePlayerSelector extends MultiplePlayerSelector {
/**
* @param entities The List of Bukkit {@link Entity}s to construct the {@link EntitySelector} from
*/
public SinglePlayerSelector(final List<Entity> entities) {
super(entities);
if (getPlayers().size() > 1) {
throw new IllegalArgumentException("More than 1 player selected in single player selector.");
}
}
/**
* @return Gets the single player parsed by the selector
*/
public Player getPlayer() {
return this.getPlayers().get(0);
}
}

View file

@ -0,0 +1,28 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
/**
* Entity Selector argument types
*/
package cloud.commandframework.bukkit.arguments.selector;

View file

@ -0,0 +1,145 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.bukkit.parsers.selector;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.bukkit.arguments.selector.MultipleEntitySelector;
import cloud.commandframework.context.CommandContext;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.function.BiFunction;
public final class MultipleEntitySelectorArgument<C> extends CommandArgument<C, MultipleEntitySelector> {
private MultipleEntitySelectorArgument(final boolean required,
@NonNull final String name,
@NonNull final String defaultValue,
@Nullable final BiFunction<@NonNull CommandContext<C>, @NonNull String,
@NonNull List<@NonNull String>> suggestionsProvider) {
super(required, name, new MultipleEntitySelectorParser<>(), defaultValue, MultipleEntitySelector.class,
suggestionsProvider);
}
/**
* Create a new builder
*
* @param name Name of the argument
* @param <C> Command sender type
* @return Created builder
*/
public static <C> MultipleEntitySelectorArgument.Builder<C> newBuilder(@NonNull final String name) {
return new MultipleEntitySelectorArgument.Builder<>(name);
}
/**
* Create a new required command argument
*
* @param name Argument name
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, MultipleEntitySelector> of(@NonNull final String name) {
return MultipleEntitySelectorArgument.<C>newBuilder(name).asRequired().build();
}
/**
* Create a new optional command argument
*
* @param name Argument name
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, MultipleEntitySelector> optional(@NonNull final String name) {
return MultipleEntitySelectorArgument.<C>newBuilder(name).asOptional().build();
}
/**
* Create a new required command argument with a default value
*
* @param name Argument name
* @param defaultEntitySelector Default player
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, MultipleEntitySelector> optional(@NonNull final String name,
@NonNull final String defaultEntitySelector) {
return MultipleEntitySelectorArgument.<C>newBuilder(name).asOptionalWithDefault(defaultEntitySelector).build();
}
public static final class Builder<C> extends CommandArgument.Builder<C, MultipleEntitySelector> {
protected Builder(@NonNull final String name) {
super(MultipleEntitySelector.class, name);
}
/**
* Builder a new argument
*
* @return Constructed argument
*/
@Override
public @NonNull MultipleEntitySelectorArgument<C> build() {
return new MultipleEntitySelectorArgument<>(this.isRequired(), this.getName(), this.getDefaultValue(),
this.getSuggestionsProvider());
}
}
public static final class MultipleEntitySelectorParser<C> implements ArgumentParser<C, MultipleEntitySelector> {
@Override
public @NonNull ArgumentParseResult<MultipleEntitySelector> parse(@NonNull final CommandContext<C> commandContext,
@NonNull final Queue<@NonNull String> inputQueue) {
if (!((Set<CloudBukkitCapabilities>) commandContext.get("CloudBukkitCapabilities")).contains(
CloudBukkitCapabilities.BRIGADIER)) {
return ArgumentParseResult.failure(
new IllegalArgumentException("Entity selector argument type not supported below Minecraft 1.13."));
}
final String input = inputQueue.peek();
if (input == null) {
return ArgumentParseResult.failure(new NullPointerException("No input was provided"));
}
inputQueue.remove();
List<Entity> entities;
try {
entities = Bukkit.selectEntities(commandContext.get("BukkitCommandSender"), input);
} catch (IllegalArgumentException e) {
return ArgumentParseResult.failure(new SelectorParseException(input));
}
return ArgumentParseResult.success(new MultipleEntitySelector(entities));
}
}
}

View file

@ -0,0 +1,172 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.bukkit.parsers.selector;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector;
import cloud.commandframework.bukkit.parsers.PlayerArgument;
import cloud.commandframework.context.CommandContext;
import com.google.common.collect.ImmutableList;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.function.BiFunction;
public final class MultiplePlayerSelectorArgument<C> extends CommandArgument<C, MultiplePlayerSelector> {
private MultiplePlayerSelectorArgument(final boolean required,
@NonNull final String name,
@NonNull final String defaultValue,
@Nullable final BiFunction<@NonNull CommandContext<C>, @NonNull String,
@NonNull List<@NonNull String>> suggestionsProvider) {
super(required, name, new MultiplePlayerSelectorParser<>(), defaultValue, MultiplePlayerSelector.class,
suggestionsProvider);
}
/**
* Create a new builder
*
* @param name Name of the argument
* @param <C> Command sender type
* @return Created builder
*/
public static <C> MultiplePlayerSelectorArgument.Builder<C> newBuilder(@NonNull final String name) {
return new MultiplePlayerSelectorArgument.Builder<>(name);
}
/**
* Create a new required command argument
*
* @param name Argument name
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, MultiplePlayerSelector> of(@NonNull final String name) {
return MultiplePlayerSelectorArgument.<C>newBuilder(name).asRequired().build();
}
/**
* Create a new optional command argument
*
* @param name Argument name
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, MultiplePlayerSelector> optional(@NonNull final String name) {
return MultiplePlayerSelectorArgument.<C>newBuilder(name).asOptional().build();
}
/**
* Create a new required command argument with a default value
*
* @param name Argument name
* @param defaultEntitySelector Default player
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, MultiplePlayerSelector> optional(@NonNull final String name,
@NonNull final String defaultEntitySelector) {
return MultiplePlayerSelectorArgument.<C>newBuilder(name).asOptionalWithDefault(defaultEntitySelector).build();
}
public static final class Builder<C> extends CommandArgument.Builder<C, MultiplePlayerSelector> {
protected Builder(@NonNull final String name) {
super(MultiplePlayerSelector.class, name);
}
/**
* Builder a new argument
*
* @return Constructed argument
*/
@Override
public @NonNull MultiplePlayerSelectorArgument<C> build() {
return new MultiplePlayerSelectorArgument<>(this.isRequired(), this.getName(), this.getDefaultValue(),
this.getSuggestionsProvider());
}
}
public static final class MultiplePlayerSelectorParser<C> implements ArgumentParser<C, MultiplePlayerSelector> {
@Override
public @NonNull ArgumentParseResult<MultiplePlayerSelector> parse(@NonNull final CommandContext<C> commandContext,
@NonNull final Queue<@NonNull String> inputQueue) {
final String input = inputQueue.peek();
if (input == null) {
return ArgumentParseResult.failure(new NullPointerException("No input was provided"));
}
inputQueue.remove();
if (!((Set<CloudBukkitCapabilities>) commandContext.get("CloudBukkitCapabilities")).contains(
CloudBukkitCapabilities.BRIGADIER)) {
Player player = Bukkit.getPlayer(input);
if (player == null) {
return ArgumentParseResult.failure(new PlayerArgument.PlayerParseException(input));
}
return ArgumentParseResult.success(new MultiplePlayerSelector(ImmutableList.of(player)));
}
List<Entity> entities;
try {
entities = Bukkit.selectEntities(commandContext.get("BukkitCommandSender"), input);
} catch (IllegalArgumentException e) {
return ArgumentParseResult.failure(new SelectorParseException(input));
}
for (Entity e : entities) {
if (!(e instanceof Player)) {
return ArgumentParseResult.failure(new IllegalArgumentException("Non-players selected in player selector."));
}
}
return ArgumentParseResult.success(new MultiplePlayerSelector(entities));
}
@Override
public @NonNull List<@NonNull String> suggestions(@NonNull final CommandContext<C> commandContext,
@NonNull final String input) {
List<String> output = new ArrayList<>();
for (Player player : Bukkit.getOnlinePlayers()) {
output.add(player.getName());
}
return output;
}
}
}

View file

@ -0,0 +1,57 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.bukkit.parsers.selector;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* EntitySelector parse exception
*/
public final class SelectorParseException extends IllegalArgumentException {
private final String input;
/**
* Construct a new EntitySelector parse exception
*
* @param input String input
*/
public SelectorParseException(@NonNull final String input) {
this.input = input;
}
/**
* Get the supplied input
*
* @return String value
*/
public @NonNull String getInput() {
return input;
}
@Override
public String getMessage() {
return String.format("Selector '%s' is malformed.", input);
}
}

View file

@ -0,0 +1,149 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.bukkit.parsers.selector;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector;
import cloud.commandframework.context.CommandContext;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.function.BiFunction;
public final class SingleEntitySelectorArgument<C> extends CommandArgument<C, SingleEntitySelector> {
private SingleEntitySelectorArgument(final boolean required,
@NonNull final String name,
@NonNull final String defaultValue,
@Nullable final BiFunction<@NonNull CommandContext<C>, @NonNull String,
@NonNull List<@NonNull String>> suggestionsProvider) {
super(required, name, new SingleEntitySelectorParser<>(), defaultValue, SingleEntitySelector.class, suggestionsProvider);
}
/**
* Create a new builder
*
* @param name Name of the argument
* @param <C> Command sender type
* @return Created builder
*/
public static <C> SingleEntitySelectorArgument.Builder<C> newBuilder(@NonNull final String name) {
return new SingleEntitySelectorArgument.Builder<>(name);
}
/**
* Create a new required command argument
*
* @param name Argument name
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, SingleEntitySelector> of(@NonNull final String name) {
return SingleEntitySelectorArgument.<C>newBuilder(name).asRequired().build();
}
/**
* Create a new optional command argument
*
* @param name Argument name
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, SingleEntitySelector> optional(@NonNull final String name) {
return SingleEntitySelectorArgument.<C>newBuilder(name).asOptional().build();
}
/**
* Create a new required command argument with a default value
*
* @param name Argument name
* @param defaultEntitySelector Default player
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, SingleEntitySelector> optional(@NonNull final String name,
@NonNull final String defaultEntitySelector) {
return SingleEntitySelectorArgument.<C>newBuilder(name).asOptionalWithDefault(defaultEntitySelector).build();
}
public static final class Builder<C> extends CommandArgument.Builder<C, SingleEntitySelector> {
protected Builder(@NonNull final String name) {
super(SingleEntitySelector.class, name);
}
/**
* Builder a new argument
*
* @return Constructed argument
*/
@Override
public @NonNull SingleEntitySelectorArgument<C> build() {
return new SingleEntitySelectorArgument<>(this.isRequired(), this.getName(), this.getDefaultValue(),
this.getSuggestionsProvider());
}
}
public static final class SingleEntitySelectorParser<C> implements ArgumentParser<C, SingleEntitySelector> {
@Override
public @NonNull ArgumentParseResult<SingleEntitySelector> parse(@NonNull final CommandContext<C> commandContext,
@NonNull final Queue<@NonNull String> inputQueue) {
if (!((Set<CloudBukkitCapabilities>) commandContext.get("CloudBukkitCapabilities")).contains(
CloudBukkitCapabilities.BRIGADIER)) {
return ArgumentParseResult.failure(
new IllegalArgumentException("Entity selector argument type not supported below Minecraft 1.13."));
}
final String input = inputQueue.peek();
if (input == null) {
return ArgumentParseResult.failure(new NullPointerException("No input was provided"));
}
inputQueue.remove();
List<Entity> entities;
try {
entities = Bukkit.selectEntities(commandContext.get("BukkitCommandSender"), input);
} catch (IllegalArgumentException e) {
return ArgumentParseResult.failure(new SelectorParseException(input));
}
if (entities.size() > 1) {
return ArgumentParseResult.failure(
new IllegalArgumentException("More than 1 entity selected in single entity selector."));
}
return ArgumentParseResult.success(new SingleEntitySelector(entities));
}
}
}

View file

@ -0,0 +1,175 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.bukkit.parsers.selector;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.bukkit.arguments.selector.SinglePlayerSelector;
import cloud.commandframework.bukkit.parsers.PlayerArgument;
import cloud.commandframework.context.CommandContext;
import com.google.common.collect.ImmutableList;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.function.BiFunction;
public final class SinglePlayerSelectorArgument<C> extends CommandArgument<C, SinglePlayerSelector> {
private SinglePlayerSelectorArgument(final boolean required,
@NonNull final String name,
@NonNull final String defaultValue,
@Nullable final BiFunction<@NonNull CommandContext<C>, @NonNull String,
@NonNull List<@NonNull String>> suggestionsProvider) {
super(required, name, new SinglePlayerSelectorParser<>(), defaultValue, SinglePlayerSelector.class, suggestionsProvider);
}
/**
* Create a new builder
*
* @param name Name of the argument
* @param <C> Command sender type
* @return Created builder
*/
public static <C> SinglePlayerSelectorArgument.Builder<C> newBuilder(@NonNull final String name) {
return new SinglePlayerSelectorArgument.Builder<>(name);
}
/**
* Create a new required command argument
*
* @param name Argument name
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, SinglePlayerSelector> of(@NonNull final String name) {
return SinglePlayerSelectorArgument.<C>newBuilder(name).asRequired().build();
}
/**
* Create a new optional command argument
*
* @param name Argument name
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, SinglePlayerSelector> optional(@NonNull final String name) {
return SinglePlayerSelectorArgument.<C>newBuilder(name).asOptional().build();
}
/**
* Create a new required command argument with a default value
*
* @param name Argument name
* @param defaultEntitySelector Default player
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull CommandArgument<C, SinglePlayerSelector> optional(@NonNull final String name,
@NonNull final String defaultEntitySelector) {
return SinglePlayerSelectorArgument.<C>newBuilder(name).asOptionalWithDefault(defaultEntitySelector).build();
}
public static final class Builder<C> extends CommandArgument.Builder<C, SinglePlayerSelector> {
protected Builder(@NonNull final String name) {
super(SinglePlayerSelector.class, name);
}
/**
* Builder a new argument
*
* @return Constructed argument
*/
@Override
public @NonNull SinglePlayerSelectorArgument<C> build() {
return new SinglePlayerSelectorArgument<>(this.isRequired(), this.getName(), this.getDefaultValue(),
this.getSuggestionsProvider());
}
}
public static final class SinglePlayerSelectorParser<C> implements ArgumentParser<C, SinglePlayerSelector> {
@Override
public @NonNull ArgumentParseResult<SinglePlayerSelector> parse(@NonNull final CommandContext<C> commandContext,
@NonNull final Queue<@NonNull String> inputQueue) {
final String input = inputQueue.peek();
if (input == null) {
return ArgumentParseResult.failure(new NullPointerException("No input was provided"));
}
inputQueue.remove();
if (!((Set<CloudBukkitCapabilities>) commandContext.get("CloudBukkitCapabilities")).contains(
CloudBukkitCapabilities.BRIGADIER)) {
Player player = Bukkit.getPlayer(input);
if (player == null) {
return ArgumentParseResult.failure(new PlayerArgument.PlayerParseException(input));
}
return ArgumentParseResult.success(new SinglePlayerSelector(ImmutableList.of(player)));
}
List<Entity> entities;
try {
entities = Bukkit.selectEntities(commandContext.get("BukkitCommandSender"), input);
} catch (IllegalArgumentException e) {
return ArgumentParseResult.failure(new SelectorParseException(input));
}
for (Entity e : entities) {
if (!(e instanceof Player)) {
return ArgumentParseResult.failure(new IllegalArgumentException("Non-players selected in player selector."));
}
}
if (entities.size() > 1) {
return ArgumentParseResult.failure(
new IllegalArgumentException("More than 1 player selected in single player selector"));
}
return ArgumentParseResult.success(new SinglePlayerSelector(entities));
}
@Override
public @NonNull List<@NonNull String> suggestions(@NonNull final CommandContext<C> commandContext,
@NonNull final String input) {
List<String> output = new ArrayList<>();
for (Player player : Bukkit.getOnlinePlayers()) {
output.add(player.getName());
}
return output;
}
}
}

View file

@ -0,0 +1,28 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
/**
* Entity Selector parsers
*/
package cloud.commandframework.bukkit.parsers.selector;

View file

@ -23,13 +23,17 @@
//
package cloud.commandframework.paper;
import cloud.commandframework.brigadier.CloudBrigadierManager;
import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource;
import com.destroystokyo.paper.event.brigadier.CommandRegisteredEvent;
import cloud.commandframework.CommandTree;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.brigadier.CloudBrigadierManager;
import cloud.commandframework.bukkit.arguments.selector.MultipleEntitySelector;
import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector;
import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector;
import cloud.commandframework.bukkit.arguments.selector.SinglePlayerSelector;
import cloud.commandframework.context.CommandContext;
import cloud.commandframework.permission.CommandPermission;
import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource;
import com.destroystokyo.paper.event.brigadier.CommandRegisteredEvent;
import com.mojang.brigadier.arguments.ArgumentType;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@ -43,6 +47,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.UUID;
import java.util.function.BiPredicate;
import java.util.function.Supplier;
import java.util.logging.Level;
class PaperBrigadierListener<C> implements Listener {
@ -75,6 +80,11 @@ class PaperBrigadierListener<C> implements Listener {
this.mapSimpleNMS(EntityType.class, this.getNMSArgument("EntitySummon").getConstructor());
/* Map Material */
this.mapSimpleNMS(Material.class, this.getNMSArgument("ItemStack").getConstructor());
/* Map Entity Selectors */
this.mapComplexNMS(SingleEntitySelector.class, this.getEntitySelectorArgument(true, false));
this.mapComplexNMS(SinglePlayerSelector.class, this.getEntitySelectorArgument(true, true));
this.mapComplexNMS(MultipleEntitySelector.class, this.getEntitySelectorArgument(false, false));
this.mapComplexNMS(MultiplePlayerSelector.class, this.getEntitySelectorArgument(false, true));
} catch (final Exception e) {
this.paperCommandManager.getOwningPlugin()
.getLogger()
@ -82,6 +92,24 @@ class PaperBrigadierListener<C> implements Listener {
}
}
/**
* @param single Whether the selector is for a single entity only (true), or for multiple entities (false)
* @param playersOnly Whether the selector is for players only (true), or for all entities (false)
* @return The NMS ArgumentType
*/
private Supplier<ArgumentType<?>> getEntitySelectorArgument(final boolean single, final boolean playersOnly) {
return () -> {
try {
Constructor<?> constructor = this.getNMSArgument("Entity").getDeclaredConstructors()[0];
constructor.setAccessible(true);
return (ArgumentType<?>) constructor.newInstance(single, playersOnly);
} catch (Exception e) {
this.paperCommandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Selector Argument", e);
return null;
}
};
}
/**
* Attempt to retrieve an NMS argument type
*
@ -119,6 +147,24 @@ class PaperBrigadierListener<C> implements Listener {
}
}
/**
* Attempt to register a mapping between a type and a NMS argument type
*
* @param type Type to map
* @param argumentTypeSupplier Supplier of the NMS argument type
*/
public void mapComplexNMS(@Nonnull final Class<?> type,
@Nonnull final Supplier<ArgumentType<?>> argumentTypeSupplier) {
try {
this.brigadierManager.registerDefaultArgumentTypeSupplier(type, argumentTypeSupplier);
} catch (final Exception e) {
this.paperCommandManager.getOwningPlugin()
.getLogger()
.warning(String.format("Failed to map '%s' to a Mojang serializable argument type",
type.getCanonicalName()));
}
}
@EventHandler
public void onCommandRegister(@Nonnull final CommandRegisteredEvent<BukkitBrigadierCommandSource> event) {
final CommandTree<C> commandTree = this.paperCommandManager.getCommandTree();