Skip to content

Commit

Permalink
Added entity selector options (currently only gamemode)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pedro270707 committed Sep 23, 2023
1 parent 708ad85 commit 24ed700
Show file tree
Hide file tree
Showing 9 changed files with 406 additions and 42 deletions.
46 changes: 42 additions & 4 deletions src/main/java/net/pedroricardo/commander/CommanderHelper.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package net.pedroricardo.commander;

import com.mojang.brigadier.Message;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.core.net.command.Command;
import net.minecraft.core.net.command.Commands;
import net.pedroricardo.commander.content.CommanderCommandManager;

import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;

public class CommanderHelper {
private static Collection<Integer> IGNORABLE_KEYS = Arrays.asList(
Expand Down Expand Up @@ -70,4 +72,40 @@ public static List<Suggestion> getLegacySuggestionList(String message, int curso
public static boolean isIgnorableKey(int key) {
return IGNORABLE_KEYS.contains(key);
}

public static CompletableFuture<Suggestions> suggest(Iterable<String> iterable, SuggestionsBuilder suggestionsBuilder) {
String string = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT);
for (String string2 : iterable) {
if (!matchesSubStr(string, string2.toLowerCase(Locale.ROOT))) continue;
suggestionsBuilder.suggest(string2);
}
return suggestionsBuilder.buildFuture();
}

public static boolean matchesSubStr(String string, String string2) {
int i = 0;
while (!string2.startsWith(string, i)) {
if ((i = string2.indexOf(95, i)) < 0) {
return false;
}
++i;
}
return true;
}

public static Optional<String> getStringToSuggest(String checkedString, String input) {
if (checkedString.startsWith(input)) {
return Optional.of(checkedString);
} else if (checkedString.substring(checkedString.indexOf('.') + 1).startsWith(input)) {
return Optional.of(checkedString.substring(checkedString.indexOf('.') + 1));
}
return Optional.empty();
}

public static boolean matchesKeyString(String checkedString, String input) {
if (checkedString.equals(input)) {
return true;
}
return checkedString.substring(checkedString.indexOf('.') + 1).equals(input);
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package net.pedroricardo.commander.content.arguments;

import com.google.common.collect.Iterables;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.core.entity.Entity;
import net.minecraft.core.entity.player.EntityPlayer;
import net.minecraft.core.lang.I18n;
import net.pedroricardo.commander.Commander;
import net.pedroricardo.commander.CommanderHelper;
import net.pedroricardo.commander.content.CommanderCommandSource;
import net.pedroricardo.commander.content.exceptions.CommanderExceptions;
import net.pedroricardo.commander.content.helpers.EntitySelector;
import net.pedroricardo.commander.content.helpers.EntitySelectorParser;

import java.util.Collection;
import java.util.concurrent.CompletableFuture;

public class EntityArgumentType implements ArgumentType<EntitySelector> {
Expand Down Expand Up @@ -62,21 +61,21 @@ public EntitySelector parse(StringReader reader) throws CommandSyntaxException {

@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
if ("@p".startsWith(builder.getRemainingLowerCase()))
builder.suggest("@p", () -> I18n.getInstance().translateKey("argument_types.commander.entity.selector.nearest_player"));
if ("@a".startsWith(builder.getRemainingLowerCase()))
builder.suggest("@a", () -> I18n.getInstance().translateKey("argument_types.commander.entity.selector.all_players"));
if ("@r".startsWith(builder.getRemainingLowerCase()))
builder.suggest("@r", () -> I18n.getInstance().translateKey("argument_types.commander.entity.selector.random_player"));
if ("@s".startsWith(builder.getRemainingLowerCase()))
builder.suggest("@s", () -> I18n.getInstance().translateKey("argument_types.commander.entity.selector.self"));
if ("@e".startsWith(builder.getRemainingLowerCase()))
builder.suggest("@e", () -> I18n.getInstance().translateKey("argument_types.commander.entity.selector.all_entities"));
for (String name : ((CommanderCommandSource)context.getSource()).getEntitySuggestions()) {
if (name.toLowerCase().startsWith(builder.getRemainingLowerCase())) {
builder.suggest(name);
}
S s = context.getSource();
if (s instanceof CommanderCommandSource) {
CommanderCommandSource source = (CommanderCommandSource)s;
StringReader stringReader = new StringReader(builder.getInput());
stringReader.setCursor(builder.getStart());
EntitySelectorParser entitySelectorParser = new EntitySelectorParser(stringReader, source.hasAdmin());
try {
entitySelectorParser.parse();
} catch (CommandSyntaxException ignored) {}
return entitySelectorParser.fillSuggestions(builder, suggestionsBuilder -> {
Collection<String> collection = source.getPlayerNames();
Iterable<String> iterable = this.playerOnly ? collection : Iterables.concat(collection, source.getEntitySuggestions());
CommanderHelper.suggest(iterable, suggestionsBuilder);
});
}
return builder.buildFuture();
return Suggestions.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static void register(CommandDispatcher<CommanderCommandSource> dispatcher
List<? extends Entity> entities = c.getArgument("entities", EntitySelector.class).get((CommanderCommandSource) c.getSource());
Achievement achievement = c.getArgument("achievement", Achievement.class);

if (entities.size() == 1 && ((EntityPlayer)entities.get(0)).getStat(achievement) == 1) {
if (entities.size() == 1 && ((EntityPlayer)entities.get(0)).getStat(achievement) != 0) {
throw PLAYER_ALREADY_HAS_ACHIEVEMENT.create();
}
if (entities.size() == 0) {
Expand All @@ -58,7 +58,7 @@ public static void register(CommandDispatcher<CommanderCommandSource> dispatcher

return CommanderCommandManager.SINGLE_SUCCESS;
}))
.then((LiteralArgumentBuilder)LiteralArgumentBuilder.literal("all")
.then((LiteralArgumentBuilder)LiteralArgumentBuilder.literal("*")
.executes(c -> {
List<? extends Entity> entities = c.getArgument("entities", EntitySelector.class).get((CommanderCommandSource) c.getSource());

Expand All @@ -78,15 +78,28 @@ public static void register(CommandDispatcher<CommanderCommandSource> dispatcher
}
}
}

sendWildcardContextualMessage(((CommanderCommandSource)c.getSource()), entities);

return CommanderCommandManager.SINGLE_SUCCESS;
}))))));
}

private static void sendContextualMessage(CommanderCommandSource source, List<? extends Entity> entities, Achievement achievement) {
private static void sendContextualMessage(CommanderCommandSource source, List<? extends Entity> entities, Achievement achievement) throws CommandSyntaxException {
if (entities.size() > 1) {
source.sendMessage(I18n.getInstance().translateKeyAndFormat("commands.commander.achievement.grant.success_multiple_entities", achievement.getStatName(), entities.size()));
} else if (entities.size() == 1) {
source.sendMessage(I18n.getInstance().translateKeyAndFormat("commands.commander.achievement.grant.success_single_entity", achievement.getStatName().trim(), ((EntityLiving)entities.get(0)).getDisplayName()));
} else {
throw CommanderExceptions.emptySelector().create();
}
}

private static void sendWildcardContextualMessage(CommanderCommandSource source, List<? extends Entity> entities) {
if (entities.size() > 1) {
source.sendMessage(I18n.getInstance().translateKeyAndFormat("commands.commander.achievement.grant.all.success_multiple_entities", entities.size()));
} else if (entities.size() == 1) {
source.sendMessage(I18n.getInstance().translateKeyAndFormat("commands.commander.achievement.grant.all.success_single_entity", ((EntityLiving)entities.get(0)).getDisplayName()));
} else {
source.sendMessage(I18n.getInstance().translateKey("commands.commander.achievement.grant.failure_empty_selector"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import net.pedroricardo.commander.content.arguments.BlockArgumentType;
import net.pedroricardo.commander.content.arguments.BlockCoordinatesArgumentType;
import net.pedroricardo.commander.content.arguments.EntityArgumentType;
import net.pedroricardo.commander.content.exceptions.CommanderExceptions;
import net.pedroricardo.commander.content.helpers.BlockCoordinates;
import net.pedroricardo.commander.content.helpers.EntitySelector;

Expand All @@ -30,9 +31,11 @@ public static void register(CommandDispatcher<CommanderCommandSource> dispatcher
.requires(source -> ((CommanderCommandSource)source).hasAdmin())
.executes(c -> {
EntityPlayer sender = ((CommanderCommandSource)c.getSource()).getSender();
if (sender != null) {
sender.killPlayer();
}

if (sender == null) throw CommanderExceptions.notInWorld().create();

sender.killPlayer();

return CommanderCommandManager.SINGLE_SUCCESS;
})
.then(RequiredArgumentBuilder.argument("entities", EntityArgumentType.entities())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ public static void register(CommandDispatcher<CommanderCommandSource> dispatcher
.executes(c -> {
BlockCoordinates coordinates = c.getArgument("pos", BlockCoordinates.class);
Block block = c.getArgument("block", Block.class);
Vec3d sourceCoordinates = ((CommanderCommandSource)c.getSource()).getCoordinates();
int metadata = c.getArgument("metadata", Integer.class);

((CommanderCommandSource)c.getSource()).getWorld().setBlockAndMetadataWithNotify(coordinates.getX((CommanderCommandSource)c.getSource()), coordinates.getY((CommanderCommandSource)c.getSource(), true), coordinates.getZ((CommanderCommandSource)c.getSource()), block.id, metadata);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,27 @@
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Predicate;

public class EntitySelector {
private final int maxResults;
private final boolean includesEntities;
private final BiConsumer<Entity, List<? extends Entity>> order;
private final @Nullable Class<? extends Entity> limitToType;
private final boolean currentEntity;
private final Predicate<Entity> predicate;
private final @Nullable String entityId;
private final @Nullable String playerName;

public EntitySelector(int maxResults, boolean includesEntities, BiConsumer<Entity, List<? extends Entity>> order, @Nullable Class<? extends Entity> limitToType, boolean currentEntity, @Nullable String entityId, @Nullable String playerName) {
public EntitySelector(int maxResults, boolean includesEntities, BiConsumer<Entity, List<? extends Entity>> order, @Nullable Class<? extends Entity> limitToType, boolean currentEntity, Predicate<Entity> predicate, @Nullable String entityId, @Nullable String playerName) {
this.maxResults = maxResults;
this.includesEntities = includesEntities;
this.order = order;
this.limitToType = limitToType;
this.currentEntity = currentEntity;
this.predicate = predicate;
this.entityId = entityId;
this.playerName = playerName;
}
Expand Down Expand Up @@ -73,10 +75,17 @@ public List<? extends Entity> get(CommanderCommandSource commandSource) throws C
// Sorting order
this.order.accept(commandSource.getSender(), entities);

List<Entity> listAfterPredicate = new ArrayList<>();
// Predicate
for (Entity entity : entities) {
if (!predicate.test(entity)) continue;
listAfterPredicate.add(entity);
}

// Maximum amount of results
entities = entities.subList(0, Math.min(entities.size(), this.maxResults));
listAfterPredicate = listAfterPredicate.subList(0, Math.min(listAfterPredicate.size(), this.maxResults));

return entities;
return listAfterPredicate;
}

public int getMaxResults() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package net.pedroricardo.commander.content.helpers;

import com.mojang.brigadier.Message;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.core.entity.player.EntityPlayer;
import net.minecraft.core.lang.I18n;
import net.minecraft.core.lang.text.Text;
import net.minecraft.core.lang.text.TextTranslatable;
import net.minecraft.core.player.gamemode.Gamemode;
import net.pedroricardo.commander.CommanderHelper;

import java.util.*;
import java.util.function.Predicate;

public class EntitySelectorOptions {
private static final DynamicCommandExceptionType INAPPLICABLE_OPTION = new DynamicCommandExceptionType(value -> (() -> I18n.getInstance().translateKeyAndFormat("argument_types.commander.entity.selector.options.inapplicable", value)));
private static final DynamicCommandExceptionType UNKNOWN_OPTION = new DynamicCommandExceptionType(value -> (() -> I18n.getInstance().translateKeyAndFormat("argument_types.commander.entity.selector.options.unknown", value)));
private static final DynamicCommandExceptionType UNKNOWN_GAME_MODE = new DynamicCommandExceptionType(value -> (() -> I18n.getInstance().translateKeyAndFormat("argument_types.commander.entity.selector.options.gamemode.invalid", value)));

private final StringReader reader;
private final String key;

private static final Map<String, Option> OPTIONS = new HashMap<>();

public EntitySelectorOptions(StringReader reader, String key) {
this.reader = reader;
this.key = key;
}

public static void register(String key, Modifier modifier, Predicate<EntitySelectorParser> canUse, Text description) {
OPTIONS.put(key, new Option(modifier, canUse, description));
}

static {
register("gamemode", (parser) -> {
parser.setSuggestions((builder, consumer) -> {
String string = builder.getRemaining().toLowerCase(Locale.ROOT);
boolean bl = !parser.hasGamemodeNotEquals();
boolean bl2 = true;
if (!string.isEmpty()) {
if (string.charAt(0) == '!') {
bl = false;
string = string.substring(1);
} else {
bl2 = false;
}
}
for (Gamemode gameMode : Gamemode.gamemodesList) {
if (!CommanderHelper.getStringToSuggest(gameMode.languageKey, string).isPresent()) continue;
String stringToSuggest = CommanderHelper.getStringToSuggest(gameMode.languageKey, string).get();
if (bl2) {
builder.suggest("!" + stringToSuggest);
}
if (!bl) continue;
builder.suggest(stringToSuggest);
}
return builder.buildFuture();
});
int cursor = parser.getReader().getCursor();
boolean invert = parser.shouldInvertValue();
String value = parser.getReader().readUnquotedString();

Gamemode gamemode = null;
for (Gamemode iteratedGameMode : Gamemode.gamemodesList) {
if (CommanderHelper.matchesKeyString(iteratedGameMode.languageKey, value)) {
gamemode = iteratedGameMode;
}
}
if (gamemode == null) {
parser.getReader().setCursor(cursor);
throw UNKNOWN_GAME_MODE.createWithContext(parser.getReader(), value);
}

parser.addPredicate((entity) -> {
if (!(entity instanceof EntityPlayer)) return false;
return CommanderHelper.matchesKeyString(((EntityPlayer) entity).gamemode.languageKey, value) != invert;
});

if (invert) {
parser.setHasGamemodeNotEquals(true);
} else {
parser.setHasGamemodeEquals(true);
}
}, parser -> !parser.hasGamemodeEquals(), new TextTranslatable("argument_types.commander.entity.selector.options.gamemode.description"));
}

public static Modifier get(EntitySelectorParser entitySelectorParser, String string, int i) throws CommandSyntaxException {
Option option = OPTIONS.get(string);
if (option != null) {
if (option.canUse.test(entitySelectorParser)) {
return option.modifier;
}
throw INAPPLICABLE_OPTION.createWithContext(entitySelectorParser.getReader(), string);
}
entitySelectorParser.getReader().setCursor(i);
throw UNKNOWN_OPTION.createWithContext(entitySelectorParser.getReader(), string);
}

public static void suggestNames(EntitySelectorParser entitySelectorParser, SuggestionsBuilder suggestionsBuilder) {
String string = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT);
for (Map.Entry<String, Option> entry : OPTIONS.entrySet()) {
if (!entry.getValue().canUse.test(entitySelectorParser) || !entry.getKey().toLowerCase(Locale.ROOT).startsWith(string)) continue;
suggestionsBuilder.suggest(entry.getKey() + "=", () -> entry.getValue().description.toString());
}
}

static class Option {
final Modifier modifier;
final Predicate<EntitySelectorParser> canUse;
final Text description;

Option(Modifier modifier, Predicate<EntitySelectorParser> canUse, Text description) {
this.modifier = modifier;
this.canUse = canUse;
this.description = description;
}
}

@FunctionalInterface
interface Modifier {
void handle(EntitySelectorParser parser) throws CommandSyntaxException;
}
}
Loading

0 comments on commit 24ed700

Please sign in to comment.