package net.minecraft.command.selectors.entity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import org.apache.commons.collections4.trie.PatriciaTrie;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import net.minecraft.command.IPermission;
import net.minecraft.command.SyntaxErrorException;
import net.minecraft.command.arg.ArgWrapper;
import net.minecraft.command.arg.TypedWrapper.Getter;
import net.minecraft.command.collections.Parsers;
import net.minecraft.command.collections.TypeIDs;
import net.minecraft.command.collections.Types;
import net.minecraft.command.completion.DataRequest;
import net.minecraft.command.completion.ITabCompletion;
import net.minecraft.command.completion.TCDSet;
import net.minecraft.command.completion.TabCompletion;
import net.minecraft.command.completion.TabCompletionData;
import net.minecraft.command.completion.TabCompletionData.Weighted;
import net.minecraft.command.descriptors.SelectorDescriptor;
import net.minecraft.command.descriptors.SelectorDescriptorDefault.DefaultParserData;
import net.minecraft.command.parser.CompletionParser.CompletionData;
import net.minecraft.command.parser.Parser;
import net.minecraft.command.selectors.entity.FilterList.InvertableArg;
import net.minecraft.command.selectors.entity.SelectorDescriptorEntity.ExParserData;
import net.minecraft.command.selectors.entity.SelectorEntity.SelectorType;
import net.minecraft.command.type.IDataType;
import net.minecraft.command.type.custom.TypeNullable;
import net.minecraft.command.type.custom.coordinate.TypeCoordinate;
import net.minecraft.command.type.custom.coordinate.TypeCoordinates;
import net.minecraft.command.type.custom.nbt.TypeNBTArg;
import net.minecraft.command.type.management.TypeID;
import net.minecraft.scoreboard.ScoreObjective;
import net.minecraft.server.MinecraftServer;
public final class SelectorDescriptorEntity extends SelectorDescriptor<ExParserData>
{
public static class ExParserData extends DefaultParserData
{
public InvertableArg name = null;
public InvertableArg team = null;
public InvertableArg type = null;
public PatriciaTrie<MutablePair<Getter<Integer>, Getter<Integer>>> primitiveScores = new PatriciaTrie<>();
public boolean nullScoreAllowed = true;
public ExParserData(final Parser parser)
{
super(parser);
}
}
private static final List<IDataType<?>> unnamedTypes = new ArrayList<>(4);
private static final PatriciaTrie<IDataType<?>> namedTypes = new PatriciaTrie<>();
private static final List<String> keyMapping = new ArrayList<>(4);
private static final Set<ITabCompletion> keyCompletions = new HashSet<>(18);
private static final ITabCompletion nameCompletion = new TabCompletion("name=", "name=", "name");
private static final ITabCompletion teamCompletion = new TabCompletion("team=", "team=", "team");
private static final ITabCompletion typeCompletion = new TabCompletion("type=", "type=", "type");
static
{
unnamedTypes.add(new TypeNullable<>(TypeCoordinate.typeXNC));
unnamedTypes.add(new TypeNullable<>(TypeCoordinate.typeYNC));
unnamedTypes.add(new TypeNullable<>(TypeCoordinate.typeZNC));
unnamedTypes.add(Parsers.integer);
keyMapping.add("x");
keyMapping.add("y");
keyMapping.add("z");
keyMapping.add("r");
namedTypes.put("x", TypeCoordinate.typeXNC);
namedTypes.put("y", TypeCoordinate.typeYNC);
namedTypes.put("z", TypeCoordinate.typeZNC);
namedTypes.put("r", Parsers.integer);
namedTypes.put("rm", Parsers.integer);
namedTypes.put("dx", Parsers.dbl);
namedTypes.put("dy", Parsers.dbl);
namedTypes.put("dz", Parsers.dbl);
namedTypes.put("dxyz", Types.generalType(TypeIDs.Coordinates));
namedTypes.put("c", Parsers.integer);
namedTypes.put("m", Parsers.integer);
namedTypes.put("l", Parsers.integer);
namedTypes.put("lm", Parsers.integer);
namedTypes.put("rx", Parsers.dbl);
namedTypes.put("rxm", Parsers.dbl);
namedTypes.put("ry", Parsers.dbl);
namedTypes.put("rym", Parsers.dbl);
namedTypes.put("xyz", TypeCoordinates.nonCentered);
namedTypes.put("nbt", TypeNBTArg.parserEntity);
for (final String key : namedTypes.keySet())
{
final String s = key + "=";
keyCompletions.add(new TabCompletion(s, s, key));
}
}
private final SelectorType selType;
public SelectorDescriptorEntity(final SelectorType selType)
{
super(Collections.<TypeID<?>> singleton(TypeIDs.EntityList), IPermission.unrestricted);
this.selType = selType;
}
@Override
public void complete(final TCDSet tcDataSet, final Parser parser, final int startIndex, final CompletionData cData, final ExParserData data)
{
final Set<String> keySet = new HashSet<>(keyMapping.size() - data.unnamedParams.size() + data.namedParams.size());
for (int i = 0; i < data.unnamedParams.size(); ++i)
if (keyMapping.get(i) != null)
keySet.add(keyMapping.get(i));
keySet.addAll(data.namedParams.keySet());
for (final ITabCompletion tc : keyCompletions)
if (!keySet.contains(tc.name.toLowerCase()))
TabCompletionData.addToSet(tcDataSet, startIndex, cData, tc);
if (data.name == null)
TabCompletionData.addToSet(tcDataSet, startIndex, cData, nameCompletion);
if (data.team == null)
TabCompletionData.addToSet(tcDataSet, startIndex, cData, teamCompletion);
if (data.type == null)
TabCompletionData.addToSet(tcDataSet, startIndex, cData, typeCompletion);
tcDataSet.add(new DataRequest()
{
Set<String> tcSet;
@Override
public void process()
{
final Collection<?> objectives = MinecraftServer.getServer().worldServerForDimension(0).getScoreboard().getScoreObjectives();
this.tcSet = new HashSet<>(objectives.size());
for (final Object objective : objectives)
this.tcSet.add(((ScoreObjective) objective).getDisplayName());
}
@Override
public void createCompletions(final Set<Weighted> tcDataSet)
{
for (final String tc : this.tcSet)
{
final Pair<Getter<Integer>, Getter<Integer>> score = data.primitiveScores.get(tc);
if (score == null || score.getLeft() == null)
TabCompletionData.addToSet(tcDataSet, startIndex, cData, new TabCompletion("score_" + tc + "_min")
{
@Override
public double weightOffset(final Matcher m, final CompletionData cData)
{
return -1.0;
};
});
if (score == null || score.getRight() == null)
TabCompletionData.addToSet(tcDataSet, startIndex, cData, new TabCompletion("score_" + tc)
{
@Override
public double weightOffset(final Matcher m, final CompletionData cData)
{
return -1.0;
};
});
}
}
});
}
@Override
public ArgWrapper<?> construct(final ExParserData data)
{
return TypeIDs.EntityList.wrap(new SelectorEntity(this.selType, data));
}
@Override
public void parse(final Parser parser, final String key, final ExParserData data) throws SyntaxErrorException
{
final IDataType<?> valueType = namedTypes.get(key);
if (valueType != null)
{
data.namedParams.put(key, valueType.parse(parser).addToProcess(data.toProcess));
return;
}
if (key.startsWith("score_"))
{
final boolean min = key.endsWith("_min");
this.parseScore(parser, key.substring(6, key.length() - (min ? 4 : 0)), min, data);
return;
}
switch (key)
{
case "name":
data.name = FilterList.name.parse(parser, data);
return;
case "team":
data.team = FilterList.team.parse(parser, data);
return;
case "type":
data.type = FilterList.type.parse(parser, data);
return;
}
throw parser.SEE("Unknown parameter key '" + key + "' encountered ");
}
private final void parseScore(final Parser parser, final String name, final boolean min, final ExParserData data) throws SyntaxErrorException
{
final Getter<Integer> value = Parsers.integer.parse(parser).addToProcess(data.toProcess).get();
final MutablePair<Getter<Integer>, Getter<Integer>> scoreData = data.primitiveScores.get(name);
if (scoreData == null)
{
data.primitiveScores.put(name, new MutablePair<>(min ? value : null, min ? null : value));
return;
}
if (min)
scoreData.left = value;
else
scoreData.right = value;
}
@Override
public void parse(final Parser parser, final ExParserData data) throws SyntaxErrorException
{
if (unnamedTypes.size() <= data.unnamedParams.size())
throw data.parser.SEE("Too many unnamed parameters encountered while parsing selector (", ")");
final IDataType<?> valueType = unnamedTypes.get(data.unnamedParams.size());
final ArgWrapper<?> value = valueType.parse(parser);
data.unnamedParams.add(value.addToProcess(data.toProcess));
}
@Override
public ExParserData newParserData(final Parser parser)
{
return new ExParserData(parser);
}
}