156 lines
7.2 KiB
Java
156 lines
7.2 KiB
Java
/*
|
|
* Minecraft Forge
|
|
* Copyright (c) 2016-2019.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation version 2.1
|
|
* of the License.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
package net.minecraftforge.server.command;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.Set;
|
|
import java.util.stream.Collectors;
|
|
|
|
import com.google.common.collect.Maps;
|
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
|
import com.mojang.brigadier.builder.ArgumentBuilder;
|
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
|
|
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
|
|
|
import net.minecraft.command.CommandSource;
|
|
import net.minecraft.command.Commands;
|
|
import net.minecraft.command.ISuggestionProvider;
|
|
import net.minecraft.command.arguments.DimensionArgument;
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.util.ResourceLocation;
|
|
import net.minecraft.util.math.ChunkPos;
|
|
import net.minecraft.util.text.StringTextComponent;
|
|
import net.minecraft.util.text.TranslationTextComponent;
|
|
import net.minecraft.world.server.ServerWorld;
|
|
import net.minecraft.world.dimension.DimensionType;
|
|
import net.minecraftforge.common.DimensionManager;
|
|
import net.minecraftforge.registries.ForgeRegistries;
|
|
|
|
import org.apache.commons.lang3.tuple.MutablePair;
|
|
import org.apache.commons.lang3.tuple.Pair;
|
|
|
|
class CommandEntity
|
|
{
|
|
static ArgumentBuilder<CommandSource, ?> register()
|
|
{
|
|
return Commands.literal("entity")
|
|
.then(EntityListCommand.register()); //TODO: //Kill, spawn, etc..
|
|
}
|
|
|
|
private static class EntityListCommand
|
|
{
|
|
private static final SimpleCommandExceptionType INVALID_FILTER = new SimpleCommandExceptionType(new TranslationTextComponent("commands.forge.entity.list.invalid"));
|
|
private static final DynamicCommandExceptionType INVALID_DIMENSION = new DynamicCommandExceptionType(dim -> new TranslationTextComponent("commands.forge.entity.list.invalidworld", dim));
|
|
private static final SimpleCommandExceptionType NO_ENTITIES = new SimpleCommandExceptionType(new TranslationTextComponent("commands.forge.entity.list.none"));
|
|
static ArgumentBuilder<CommandSource, ?> register()
|
|
{
|
|
return Commands.literal("list")
|
|
.requires(cs->cs.hasPermissionLevel(2)) //permission
|
|
.then(Commands.argument("filter", StringArgumentType.string())
|
|
.suggests((ctx, builder) -> ISuggestionProvider.suggest(ForgeRegistries.ENTITIES.getKeys().stream().map(id -> id.toString()), builder))
|
|
.then(Commands.argument("dim", DimensionArgument.getDimension())
|
|
.executes(ctx -> execute(ctx.getSource(), StringArgumentType.getString(ctx, "filter"), DimensionArgument.getDimensionArgument(ctx, "dim")))
|
|
)
|
|
.executes(ctx -> execute(ctx.getSource(), StringArgumentType.getString(ctx, "filter"), ctx.getSource().getWorld().dimension.getType()))
|
|
)
|
|
.executes(ctx -> execute(ctx.getSource(), "*", ctx.getSource().getWorld().dimension.getType()));
|
|
}
|
|
|
|
private static int execute(CommandSource sender, String filter, DimensionType dim) throws CommandSyntaxException
|
|
{
|
|
final String cleanFilter = filter.replace("?", ".?").replace("*", ".*?");
|
|
|
|
Set<ResourceLocation> names = ForgeRegistries.ENTITIES.getKeys().stream().filter(n -> n.toString().matches(cleanFilter)).collect(Collectors.toSet());
|
|
|
|
if (names.isEmpty())
|
|
throw INVALID_FILTER.create();
|
|
|
|
ServerWorld world = DimensionManager.getWorld(sender.getServer(), dim, false, false);
|
|
if (world == null)
|
|
throw INVALID_DIMENSION.create(dim);
|
|
|
|
Map<ResourceLocation, MutablePair<Integer, Map<ChunkPos, Integer>>> list = Maps.newHashMap();
|
|
world.getEntities().forEach(e -> {
|
|
MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(e.getType().getRegistryName(), k -> MutablePair.of(0, Maps.newHashMap()));
|
|
ChunkPos chunk = new ChunkPos(e.getPosition());
|
|
info.left++;
|
|
info.right.put(chunk, info.right.getOrDefault(chunk, 0) + 1);
|
|
});
|
|
|
|
if (names.size() == 1)
|
|
{
|
|
ResourceLocation name = names.iterator().next();
|
|
Pair<Integer, Map<ChunkPos, Integer>> info = list.get(name);
|
|
if (info == null)
|
|
throw NO_ENTITIES.create();
|
|
|
|
sender.sendFeedback(new TranslationTextComponent("commands.forge.entity.list.single.header", name, info.getLeft()), true);
|
|
List<Map.Entry<ChunkPos, Integer>> toSort = new ArrayList<>();
|
|
toSort.addAll(info.getRight().entrySet());
|
|
toSort.sort((a, b) -> {
|
|
if (Objects.equals(a.getValue(), b.getValue()))
|
|
return a.getKey().toString().compareTo(b.getKey().toString());
|
|
else
|
|
return b.getValue() - a.getValue();
|
|
});
|
|
|
|
long limit = 10;
|
|
for (Map.Entry<ChunkPos, Integer> e : toSort)
|
|
{
|
|
if (limit-- == 0) break;
|
|
sender.sendFeedback(new StringTextComponent(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z), true);
|
|
}
|
|
return toSort.size();
|
|
}
|
|
else
|
|
{
|
|
|
|
List<Pair<ResourceLocation, Integer>> info = new ArrayList<>();
|
|
list.forEach((key, value) -> {
|
|
if (names.contains(key))
|
|
{
|
|
Pair<ResourceLocation, Integer> of = Pair.of(key, value.left);
|
|
info.add(of);
|
|
}
|
|
});
|
|
info.sort((a, b) -> {
|
|
if (Objects.equals(a.getRight(), b.getRight()))
|
|
return a.getKey().toString().compareTo(b.getKey().toString());
|
|
else
|
|
return b.getRight() - a.getRight();
|
|
});
|
|
|
|
if (info.size() == 0)
|
|
throw NO_ENTITIES.create();
|
|
|
|
int count = info.stream().mapToInt(Pair::getRight).sum();
|
|
sender.sendFeedback(new TranslationTextComponent("commands.forge.entity.list.multiple.header", count), true);
|
|
info.forEach(e -> sender.sendFeedback(new StringTextComponent(" " + e.getValue() + ": " + e.getKey()), true));
|
|
return info.size();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|