Add new /forge entity list command for displaying a list of all entities in world.

As well as tracking down chunks with large amounts of entities.
This commit is contained in:
LexManos 2017-09-25 12:56:09 -07:00
parent 21e4803947
commit 303a775fc3
3 changed files with 107 additions and 2 deletions

View File

@ -572,7 +572,7 @@ public class GameData
RegistryEvent.MissingMappings<?> event = reg.getMissingEvent(name, m.getValue());
MinecraftForge.EVENT_BUS.post(event);
List<MissingMappings.Mapping<?>> lst = event.getAllMappings().stream().filter(e -> e.getAction() == MissingMappings.Action.DEFAULT).collect(Collectors.toList());
List<MissingMappings.Mapping<?>> lst = event.getAllMappings().stream().filter(e -> e.getAction() == MissingMappings.Action.DEFAULT).sorted((a, b) -> a.toString().compareTo(b.toString())).collect(Collectors.toList());
if (!lst.isEmpty())
{
FMLLog.log.error("Unidentified mapping from registry {}", name);

View File

@ -23,16 +23,30 @@ import java.text.DecimalFormat;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.Maps;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.WrongUsageException;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.WorldWorkerManager;
import net.minecraftforge.server.ForgeTimeTracker;
@ -86,6 +100,10 @@ public class ForgeCommand extends CommandBase {
{
handleGen(server, sender, args);
}
else if ("entity".equals(args[0]))
{
handleEntity(server, sender, args);
}
else
{
throw new WrongUsageException("commands.forge.usage");
@ -96,7 +114,7 @@ public class ForgeCommand extends CommandBase {
public List<String> getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos)
{
if (args.length <= 1)
return getListOfStringsMatchingLastWord(args, new String[] {"help", "tps", "track", "gen"});
return getListOfStringsMatchingLastWord(args, "help", "tps", "track", "gen", "entity");
switch (args[0].toLowerCase(Locale.ENGLISH))
{
@ -108,6 +126,12 @@ public class ForgeCommand extends CommandBase {
if (args.length == 6) // Dimension, Add support for names? Get list of ids? Meh
return Collections.emptyList();
break;
case "entity":
if (args.length == 2)
return getListOfStringsMatchingLastWord(args, "help", "list");
if (args.length == 3)
return getListOfStringsMatchingLastWord(args,EntityList.getEntityNameList().stream().map(e -> e.toString()).sorted().toArray(String[]::new));
break;
}
return Collections.emptyList();
}
@ -199,4 +223,78 @@ public class ForgeCommand extends CommandBase {
return sum / values.length;
}
private void handleEntity(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException
{
if (args.length < 2 || args[1].toLowerCase(Locale.ENGLISH).equals("help"))
throw new WrongUsageException("commands.forge.entity.usage");
switch (args[1].toLowerCase(Locale.ENGLISH))
{
case "list":
String filter = "*";
if (args.length > 2)
{
if (args[2].toLowerCase(Locale.ENGLISH).equals("help"))
throw new WrongUsageException("commands.forge.entity.list.usage");
filter = args[2];
}
final String cleanfilter = filter.replace("?", ".?").replace("*", ".*?");
Set<ResourceLocation> names = EntityList.getEntityNameList().stream().filter(n -> n.toString().matches(cleanfilter)).collect(Collectors.toSet());
if (names.isEmpty())
throw new WrongUsageException("commands.forge.entity.list.invalid");
int dim = args.length > 3 ? parseInt(args[3]) : sender.getEntityWorld().provider.getDimension();
Map<ResourceLocation, MutablePair<Integer, Map<ChunkPos, Integer>>> list = Maps.newHashMap();
WorldServer world = DimensionManager.getWorld(dim);
if (world == null)
throw new WrongUsageException("commands.forge.entity.list.invalidworld", dim);
List<Entity> entities = world.getLoadedEntityList();
entities.forEach(e -> {
ResourceLocation key = EntityList.getKey(e);
MutablePair<Integer, Map<ChunkPos, Integer>> info = list.get(key);
if (info == null)
{
info = MutablePair.of(0, Maps.newHashMap());
list.put(key, info);
}
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 new WrongUsageException("commands.forge.entity.list.none");
sender.sendMessage(new TextComponentTranslation("commands.forge.entity.list.single.header", name, info.getLeft()));
info.getRight().entrySet().stream()
.sorted((a,b) -> a.getValue() != b.getValue() ? b.getValue() - a.getValue() : a.getKey().toString().compareTo(b.getKey().toString()))
.limit(10).forEach(e -> sender.sendMessage(new TextComponentString(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z)));
}
else
{
List<Pair<ResourceLocation, Integer>> info = list.entrySet().stream()
.filter(e -> names.contains(e.getKey()))
.map(e -> Pair.of(e.getKey(), e.getValue().left))
.sorted((a, b) -> a.getRight() != b.getRight() ? b.getRight() - a.getRight() : a.getKey().toString().compareTo(b.getKey().toString()))
.collect(Collectors.toList());
if (info == null || info.size() == 0)
throw new WrongUsageException("commands.forge.entity.list.none");
int count = info.stream().mapToInt(a -> a.getRight()).sum();
sender.sendMessage(new TextComponentTranslation("commands.forge.entity.list.multiple.header", count));
info.forEach(e -> sender.sendMessage(new TextComponentString(" " + e.getValue() + ": " + e.getKey())));
}
break;
}
}
}

View File

@ -6,6 +6,13 @@ commands.forge.gen.dim_fail=Failed to load world for dimension %d, Task terminat
commands.forge.gen.progress=Generation Progress: %d/%d
commands.forge.gen.complete=Finished generating %d new chunks (out of %d) for dimension %d.
commands.forge.gen.start=Starting to generate %d chunks in a spiral around %d, %d in dimension %d.
commands.forge.entity.usage=Use /forge entity [list] help for more infomration on a specific command.
commands.forge.entity.list.usage=Use /forge entity list [filter] [dim] to get entity info that matches the optional filter.
commands.forge.entity.list.invalid=Invalid filter, does not match any entities. Use /forge entity list for a proper list
commands.forge.entity.list.invalidworld=Could not load world for dimension %d. Please select a valid dimension.
commands.forge.entity.list.none=No entities found.
commands.forge.entity.list.single.header=Entity: %s Total: %d
commands.forge.entity.list.multiple.header=Total: %d
commands.forge.tracking.te.enabled=Tile Entity tracking enabled for %d seconds.
commands.tree_base.invalid_cmd=Invalid subcommand '%s'!