aboutsummaryrefslogblamecommitdiff
path: root/src/main/java/org/chrisoft/trashyaddon/commands/CEntitySelectorOptions.java
blob: c49e80fc6cda614c4fd4eb3de55a190b307b10e6 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12











                                                                   
                          

                                    
                                                  
                                                     
                                                          
                                                             
                                           


                                         




                                                          




                                           
                                          
                                           
                                                  




                                                        


                                                       



                                          
                                                

                                     


























































































































































                                                                                                                                                            
 




                                                                                         
 









































                                                                                                                       
                                     












































                                                                                                                                            
 


































































                                                                                                                                                            
 




































                                                                                                                   
 



















                                                                                                                 
                                            



















                                                                                                            
                         

















































                                                                                                                                                                   
             











                                                                                                                        
             





                                                                                
 

                                                                                                                                                
 
package org.chrisoft.trashyaddon.commands;

import com.google.common.collect.Maps;
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 java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Map.Entry;
import java.util.function.Predicate;
import net.minecraft.advancement.AdvancementEntry;
import net.minecraft.advancement.AdvancementProgress;
import net.minecraft.advancement.PlayerAdvancementTracker;
import net.minecraft.advancement.criterion.CriterionProgress;
import net.minecraft.command.CommandSource;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.loot.condition.LootCondition;
import net.minecraft.loot.context.LootContext;
import net.minecraft.loot.context.LootContextParameterSet;
import net.minecraft.loot.context.LootContextParameters;
import net.minecraft.loot.context.LootContextTypes;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.nbt.StringNbtReader;
import net.minecraft.predicate.NumberRange;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.scoreboard.AbstractTeam;
import net.minecraft.scoreboard.ReadableScoreboardScore;
import net.minecraft.scoreboard.Scoreboard;
import net.minecraft.scoreboard.ScoreboardObjective;
import net.minecraft.server.ServerAdvancementLoader;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.GameMode;
import net.minecraft.command.FloatRangeArgument;

public class CEntitySelectorOptions {
    private static final Map<String, CEntitySelectorOptions.SelectorOption> OPTIONS = Maps.newHashMap();
    public static final DynamicCommandExceptionType UNKNOWN_OPTION_EXCEPTION = new DynamicCommandExceptionType(
        option -> Text.stringifiedTranslatable("argument.entity.options.unknown", option)
    );
    public static final DynamicCommandExceptionType INAPPLICABLE_OPTION_EXCEPTION = new DynamicCommandExceptionType(
        option -> Text.stringifiedTranslatable("argument.entity.options.inapplicable", option)
    );
    public static final SimpleCommandExceptionType NEGATIVE_DISTANCE_EXCEPTION = new SimpleCommandExceptionType(
        Text.translatable("argument.entity.options.distance.negative")
    );
    public static final SimpleCommandExceptionType NEGATIVE_LEVEL_EXCEPTION = new SimpleCommandExceptionType(
        Text.translatable("argument.entity.options.level.negative")
    );
    public static final SimpleCommandExceptionType TOO_SMALL_LEVEL_EXCEPTION = new SimpleCommandExceptionType(
        Text.translatable("argument.entity.options.limit.toosmall")
    );
    public static final DynamicCommandExceptionType IRREVERSIBLE_SORT_EXCEPTION = new DynamicCommandExceptionType(
        sortType -> Text.stringifiedTranslatable("argument.entity.options.sort.irreversible", sortType)
    );
    public static final DynamicCommandExceptionType INVALID_MODE_EXCEPTION = new DynamicCommandExceptionType(
        gameMode -> Text.stringifiedTranslatable("argument.entity.options.mode.invalid", gameMode)
    );
    public static final DynamicCommandExceptionType INVALID_TYPE_EXCEPTION = new DynamicCommandExceptionType(
        entity -> Text.stringifiedTranslatable("argument.entity.options.type.invalid", entity)
    );

    private static void putOption(String id, CEntitySelectorOptions.SelectorHandler handler, Predicate<CEntitySelectorReader> condition, Text description) {
        OPTIONS.put(id, new CEntitySelectorOptions.SelectorOption(handler, condition, description));
    }

    public static void register() {
        if (OPTIONS.isEmpty()) {
            putOption("name", reader -> {
                int i = reader.getReader().getCursor();
                boolean bl = reader.readNegationCharacter();
                String string = reader.getReader().readString();
                if (reader.excludesName() && !bl) {
                    reader.getReader().setCursor(i);
                    throw INAPPLICABLE_OPTION_EXCEPTION.createWithContext(reader.getReader(), "name");
                } else {
                    if (bl) {
                        reader.setExcludesName(true);
                    } else {
                        reader.setSelectsName(true);
                    }

                    reader.addPredicate(entity -> entity.getName().getString().equals(string) != bl);
                }
            }, reader -> !reader.selectsName(), Text.translatable("argument.entity.options.name.description"));
            putOption("distance", reader -> {
                int i = reader.getReader().getCursor();
                NumberRange.DoubleRange lv = NumberRange.DoubleRange.parse(reader.getReader());
                if ((!lv.min().isPresent() || !(lv.min().get() < 0.0)) && (!lv.max().isPresent() || !(lv.max().get() < 0.0))) {
                    reader.setDistance(lv);
                    reader.setLocalWorldOnly();
                } else {
                    reader.getReader().setCursor(i);
                    throw NEGATIVE_DISTANCE_EXCEPTION.createWithContext(reader.getReader());
                }
            }, reader -> reader.getDistance().isDummy(), Text.translatable("argument.entity.options.distance.description"));
            putOption("level", reader -> {
                int i = reader.getReader().getCursor();
                NumberRange.IntRange lv = NumberRange.IntRange.parse(reader.getReader());
                if ((!lv.min().isPresent() || lv.min().get() >= 0) && (!lv.max().isPresent() || lv.max().get() >= 0)) {
                    reader.setLevelRange(lv);
                    reader.setIncludesNonPlayers(false);
                } else {
                    reader.getReader().setCursor(i);
                    throw NEGATIVE_LEVEL_EXCEPTION.createWithContext(reader.getReader());
                }
            }, reader -> reader.getLevelRange().isDummy(), Text.translatable("argument.entity.options.level.description"));
            putOption("x", reader -> {
                reader.setLocalWorldOnly();
                reader.setX(reader.getReader().readDouble());
            }, reader -> reader.getX() == null, Text.translatable("argument.entity.options.x.description"));
            putOption("y", reader -> {
                reader.setLocalWorldOnly();
                reader.setY(reader.getReader().readDouble());
            }, reader -> reader.getY() == null, Text.translatable("argument.entity.options.y.description"));
            putOption("z", reader -> {
                reader.setLocalWorldOnly();
                reader.setZ(reader.getReader().readDouble());
            }, reader -> reader.getZ() == null, Text.translatable("argument.entity.options.z.description"));
            putOption("dx", reader -> {
                reader.setLocalWorldOnly();
                reader.setDx(reader.getReader().readDouble());
            }, reader -> reader.getDx() == null, Text.translatable("argument.entity.options.dx.description"));
            putOption("dy", reader -> {
                reader.setLocalWorldOnly();
                reader.setDy(reader.getReader().readDouble());
            }, reader -> reader.getDy() == null, Text.translatable("argument.entity.options.dy.description"));
            putOption("dz", reader -> {
                reader.setLocalWorldOnly();
                reader.setDz(reader.getReader().readDouble());
            }, reader -> reader.getDz() == null, Text.translatable("argument.entity.options.dz.description"));
            putOption(
                "x_rotation",
                reader -> reader.setPitchRange(FloatRangeArgument.parse(reader.getReader(), true, MathHelper::wrapDegrees)),
                reader -> reader.getPitchRange() == FloatRangeArgument.ANY,
                Text.translatable("argument.entity.options.x_rotation.description")
            );
            putOption(
                "y_rotation",
                reader -> reader.setYawRange(FloatRangeArgument.parse(reader.getReader(), true, MathHelper::wrapDegrees)),
                reader -> reader.getYawRange() == FloatRangeArgument.ANY,
                Text.translatable("argument.entity.options.y_rotation.description")
            );
            putOption("limit", reader -> {
                int i = reader.getReader().getCursor();
                int j = reader.getReader().readInt();
                if (j < 1) {
                    reader.getReader().setCursor(i);
                    throw TOO_SMALL_LEVEL_EXCEPTION.createWithContext(reader.getReader());
                } else {
                    reader.setLimit(j);
                    reader.setHasLimit(true);
                }
            }, reader -> !reader.isSenderOnly() && !reader.hasLimit(), Text.translatable("argument.entity.options.limit.description"));
            putOption(
                "sort",
                reader -> {
                    int i = reader.getReader().getCursor();
                    String string = reader.getReader().readUnquotedString();
                    reader.setSuggestionProvider(
                        (builder, consumer) -> CommandSource.suggestMatching(Arrays.asList("nearest", "furthest", "random", "arbitrary"), builder)
                    );

                    reader.setSorter(switch (string) {
                        case "nearest" -> CEntitySelectorReader.NEAREST;
                        case "furthest" -> CEntitySelectorReader.FURTHEST;
                        case "random" -> CEntitySelectorReader.RANDOM;
                        case "arbitrary" -> CEntitySelector.ARBITRARY;
                        default -> {
                            reader.getReader().setCursor(i);
                            throw IRREVERSIBLE_SORT_EXCEPTION.createWithContext(reader.getReader(), string);
                        }
                    });
                    reader.setHasSorter(true);
                },
                reader -> !reader.isSenderOnly() && !reader.hasSorter(),
                Text.translatable("argument.entity.options.sort.description")
            );
            putOption("gamemode", reader -> {
                reader.setSuggestionProvider((builder, consumer) -> {
                    String stringx = builder.getRemaining().toLowerCase(Locale.ROOT);
                    boolean blx = !reader.excludesGameMode();
                    boolean bl2 = true;
                    if (!stringx.isEmpty()) {
                        if (stringx.charAt(0) == '!') {
                            blx = false;
                            stringx = stringx.substring(1);
                        } else {
                            bl2 = false;
                        }
                    }

                    for (GameMode lvx : GameMode.values()) {
                        if (lvx.getName().toLowerCase(Locale.ROOT).startsWith(stringx)) {
                            if (bl2) {
                                builder.suggest("!" + lvx.getName());
                            }

                            if (blx) {
                                builder.suggest(lvx.getName());
                            }
                        }
                    }

                    return builder.buildFuture();
                });
                int i = reader.getReader().getCursor();
                boolean bl = reader.readNegationCharacter();
                if (reader.excludesGameMode() && !bl) {
                    reader.getReader().setCursor(i);
                    throw INAPPLICABLE_OPTION_EXCEPTION.createWithContext(reader.getReader(), "gamemode");
                } else {
                    String string = reader.getReader().readUnquotedString();
                    GameMode lv = GameMode.byName(string, null);
                    if (lv == null) {
                        reader.getReader().setCursor(i);
                        throw INVALID_MODE_EXCEPTION.createWithContext(reader.getReader(), string);
                    } else {
                        reader.setIncludesNonPlayers(false);
                        reader.addPredicate(entity -> {
                            if (!(entity instanceof ServerPlayerEntity)) {
                                return false;
                            } else {
                                GameMode lvx = ((ServerPlayerEntity)entity).interactionManager.getGameMode();
                                return bl ? lvx != lv : lvx == lv;
                            }
                        });
                        if (bl) {
                            reader.setExcludesGameMode(true);
                        } else {
                            reader.setSelectsGameMode(true);
                        }
                    }
                }
            }, reader -> !reader.selectsGameMode(), Text.translatable("argument.entity.options.gamemode.description"));
            putOption("team", reader -> {
                boolean bl = reader.readNegationCharacter();
                String string = reader.getReader().readUnquotedString();
                reader.addPredicate(entity -> {
                    if (!(entity instanceof LivingEntity)) {
                        return false;
                    } else {
                        AbstractTeam lv = entity.getScoreboardTeam();
                        String string2 = lv == null ? "" : lv.getName();
                        return string2.equals(string) != bl;
                    }
                });
                if (bl) {
                    reader.setExcludesTeam(true);
                } else {
                    reader.setSelectsTeam(true);
                }
            }, reader -> !reader.selectsTeam(), Text.translatable("argument.entity.options.team.description"));
            putOption("type", reader -> {
                reader.setSuggestionProvider((builder, consumer) -> {
                    CommandSource.suggestIdentifiers(Registries.ENTITY_TYPE.getIds(), builder, String.valueOf('!'));
                    CommandSource.suggestIdentifiers(Registries.ENTITY_TYPE.streamTags().map(TagKey::id), builder, "!#");
                    if (!reader.excludesEntityType()) {
                        CommandSource.suggestIdentifiers(Registries.ENTITY_TYPE.getIds(), builder);
                        CommandSource.suggestIdentifiers(Registries.ENTITY_TYPE.streamTags().map(TagKey::id), builder, String.valueOf('#'));
                    }

                    return builder.buildFuture();
                });
                int i = reader.getReader().getCursor();
                boolean bl = reader.readNegationCharacter();
                if (reader.excludesEntityType() && !bl) {
                    reader.getReader().setCursor(i);
                    throw INAPPLICABLE_OPTION_EXCEPTION.createWithContext(reader.getReader(), "type");
                } else {
                    if (bl) {
                        reader.setExcludesEntityType();
                    }

                    if (reader.readTagCharacter()) {
                        TagKey<EntityType<?>> lv = TagKey.of(RegistryKeys.ENTITY_TYPE, Identifier.fromCommandInput(reader.getReader()));
                        reader.addPredicate(entity -> entity.getType().isIn(lv) != bl);
                    } else {
                        Identifier lv2 = Identifier.fromCommandInput(reader.getReader());
                        EntityType<?> lv3 = Registries.ENTITY_TYPE.getOrEmpty(lv2).orElseThrow(() -> {
                            reader.getReader().setCursor(i);
                            return INVALID_TYPE_EXCEPTION.createWithContext(reader.getReader(), lv2.toString());
                        });
                        if (Objects.equals(EntityType.PLAYER, lv3) && !bl) {
                            reader.setIncludesNonPlayers(false);
                        }

                        reader.addPredicate(entity -> Objects.equals(lv3, entity.getType()) != bl);
                        if (!bl) {
                            reader.setEntityType(lv3);
                        }
                    }
                }
            }, reader -> !reader.selectsEntityType(), Text.translatable("argument.entity.options.type.description"));
            putOption("tag", reader -> {
                boolean bl = reader.readNegationCharacter();
                String string = reader.getReader().readUnquotedString();
                reader.addPredicate(entity -> "".equals(string) ? entity.getCommandTags().isEmpty() != bl : entity.getCommandTags().contains(string) != bl);
            }, reader -> true, Text.translatable("argument.entity.options.tag.description"));
            putOption("nbt", reader -> {
                boolean bl = reader.readNegationCharacter();
                NbtCompound lv = new StringNbtReader(reader.getReader()).parseCompound();
                reader.addPredicate(entity -> {
                    NbtCompound lvx = entity.writeNbt(new NbtCompound());
                    if (entity instanceof ServerPlayerEntity lv2) {
                        ItemStack lv3 = lv2.getInventory().getMainHandStack();
                        if (!lv3.isEmpty()) {
                            lvx.put("SelectedItem", lv3.encode(lv2.getRegistryManager()));
                        }
                    }

                    return NbtHelper.matches(lv, lvx, true) != bl;
                });
            }, reader -> true, Text.translatable("argument.entity.options.nbt.description"));
            putOption("scores", reader -> {
                StringReader stringReader = reader.getReader();
                Map<String, NumberRange.IntRange> map = Maps.newHashMap();
                stringReader.expect('{');
                stringReader.skipWhitespace();

                while (stringReader.canRead() && stringReader.peek() != '}') {
                    stringReader.skipWhitespace();
                    String string = stringReader.readUnquotedString();
                    stringReader.skipWhitespace();
                    stringReader.expect('=');
                    stringReader.skipWhitespace();
                    NumberRange.IntRange lv = NumberRange.IntRange.parse(stringReader);
                    map.put(string, lv);
                    stringReader.skipWhitespace();
                    if (stringReader.canRead() && stringReader.peek() == ',') {
                        stringReader.skip();
                    }
                }

                stringReader.expect('}');
                if (!map.isEmpty()) {
                    reader.addPredicate(entity -> {
                        Scoreboard lvx = entity.getServer().getScoreboard();

                        for (Entry<String, NumberRange.IntRange> entry : map.entrySet()) {
                            ScoreboardObjective lv2 = lvx.getNullableObjective(entry.getKey());
                            if (lv2 == null) {
                                return false;
                            }

                            ReadableScoreboardScore lv3 = lvx.getScore(entity, lv2);
                            if (lv3 == null) {
                                return false;
                            }

                            if (!entry.getValue().test(lv3.getScore())) {
                                return false;
                            }
                        }

                        return true;
                    });
                }

                reader.setSelectsScores(true);
            }, reader -> !reader.selectsScores(), Text.translatable("argument.entity.options.scores.description"));
            putOption("advancements", reader -> {
                StringReader stringReader = reader.getReader();
                Map<Identifier, Predicate<AdvancementProgress>> map = Maps.newHashMap();
                stringReader.expect('{');
                stringReader.skipWhitespace();

                while (stringReader.canRead() && stringReader.peek() != '}') {
                    stringReader.skipWhitespace();
                    Identifier lv = Identifier.fromCommandInput(stringReader);
                    stringReader.skipWhitespace();
                    stringReader.expect('=');
                    stringReader.skipWhitespace();
                    if (stringReader.canRead() && stringReader.peek() == '{') {
                        Map<String, Predicate<CriterionProgress>> map2 = Maps.newHashMap();
                        stringReader.skipWhitespace();
                        stringReader.expect('{');
                        stringReader.skipWhitespace();

                        while (stringReader.canRead() && stringReader.peek() != '}') {
                            stringReader.skipWhitespace();
                            String string = stringReader.readUnquotedString();
                            stringReader.skipWhitespace();
                            stringReader.expect('=');
                            stringReader.skipWhitespace();
                            boolean bl = stringReader.readBoolean();
                            map2.put(string, criterionProgress -> criterionProgress.isObtained() == bl);
                            stringReader.skipWhitespace();
                            if (stringReader.canRead() && stringReader.peek() == ',') {
                                stringReader.skip();
                            }
                        }

                        stringReader.skipWhitespace();
                        stringReader.expect('}');
                        stringReader.skipWhitespace();
                        map.put(lv, advancementProgress -> {
                            for (Entry<String, Predicate<CriterionProgress>> entry : map2.entrySet()) {
                                CriterionProgress lvx = advancementProgress.getCriterionProgress(entry.getKey());
                                if (lvx == null || !entry.getValue().test(lvx)) {
                                    return false;
                                }
                            }

                            return true;
                        });
                    } else {
                        boolean bl2 = stringReader.readBoolean();
                        map.put(lv, advancementProgress -> advancementProgress.isDone() == bl2);
                    }

                    stringReader.skipWhitespace();
                    if (stringReader.canRead() && stringReader.peek() == ',') {
                        stringReader.skip();
                    }
                }

                stringReader.expect('}');
                if (!map.isEmpty()) {
                    reader.addPredicate(entity -> {
                        if (!(entity instanceof ServerPlayerEntity lvx)) {
                            return false;
                        } else {
                            PlayerAdvancementTracker lv2 = lvx.getAdvancementTracker();
                            ServerAdvancementLoader lv3 = lvx.getServer().getAdvancementLoader();

                            for (Entry<Identifier, Predicate<AdvancementProgress>> entry : map.entrySet()) {
                                AdvancementEntry lv4 = lv3.get(entry.getKey());
                                if (lv4 == null || !entry.getValue().test(lv2.getProgress(lv4))) {
                                    return false;
                                }
                            }

                            return true;
                        }
                    });
                    reader.setIncludesNonPlayers(false);
                }

                reader.setSelectsAdvancements(true);
            }, reader -> !reader.selectsAdvancements(), Text.translatable("argument.entity.options.advancements.description"));
            putOption(
                "predicate",
                reader -> {
                    boolean bl = reader.readNegationCharacter();
                    RegistryKey<LootCondition> lv = RegistryKey.of(RegistryKeys.PREDICATE, Identifier.fromCommandInput(reader.getReader()));
                    reader.addPredicate(
                        entity -> {
                            if (!(entity.getWorld() instanceof ServerWorld)) {
                                return false;
                            } else {
                                ServerWorld lvx = (ServerWorld)entity.getWorld();
                                Optional<LootCondition> optional = lvx.getServer()
                                    .getReloadableRegistries()
                                    .createRegistryLookup()
                                    .getOptionalEntry(RegistryKeys.PREDICATE, lv)
                                    .map(RegistryEntry::value);
                                if (optional.isEmpty()) {
                                    return false;
                                } else {
                                    LootContextParameterSet lv2 = new LootContextParameterSet.Builder(lvx)
                                        .add(LootContextParameters.THIS_ENTITY, entity)
                                        .add(LootContextParameters.ORIGIN, entity.getPos())
                                        .build(LootContextTypes.SELECTOR);
                                    LootContext lv3 = new LootContext.Builder(lv2).build(Optional.empty());
                                    lv3.markActive(LootContext.predicate(optional.get()));
                                    return bl ^ optional.get().test(lv3);
                                }
                            }
                        }
                    );
                },
                reader -> true,
                Text.translatable("argument.entity.options.predicate.description")
            );
        }
    }

    public static CEntitySelectorOptions.SelectorHandler getHandler(CEntitySelectorReader reader, String option, int restoreCursor) throws CommandSyntaxException {
        CEntitySelectorOptions.SelectorOption lv = OPTIONS.get(option);
        if (lv != null) {
            if (lv.condition.test(reader)) {
                return lv.handler;
            } else {
                throw INAPPLICABLE_OPTION_EXCEPTION.createWithContext(reader.getReader(), option);
            }
        } else {
            reader.getReader().setCursor(restoreCursor);
            throw UNKNOWN_OPTION_EXCEPTION.createWithContext(reader.getReader(), option);
        }
    }

    public static void suggestOptions(CEntitySelectorReader reader, SuggestionsBuilder suggestionBuilder) {
        String string = suggestionBuilder.getRemaining().toLowerCase(Locale.ROOT);

        for (Entry<String, CEntitySelectorOptions.SelectorOption> entry : OPTIONS.entrySet()) {
            if (entry.getValue().condition.test(reader) && entry.getKey().toLowerCase(Locale.ROOT).startsWith(string)) {
                suggestionBuilder.suggest(entry.getKey() + "=", entry.getValue().description);
            }
        }
    }

    public interface SelectorHandler {
        void handle(CEntitySelectorReader reader) throws CommandSyntaxException;
    }

    static record SelectorOption(CEntitySelectorOptions.SelectorHandler handler, Predicate<CEntitySelectorReader> condition, Text description) {
    }
}