/* * Copyright (C) 2022 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * * NotEnoughUpdates 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, either * version 3 of the License, or (at your option) any later version. * * NotEnoughUpdates 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 NotEnoughUpdates. If not, see . */ package io.github.moulberry.notenoughupdates.commands.dev; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.commands.ClientCommandBase; import io.github.moulberry.notenoughupdates.core.util.MiscUtils; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.command.CommandException; import net.minecraft.command.ICommandSender; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityArmorStand; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.BlockPos; import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; import java.util.HashMap; import java.util.List; import java.util.function.Supplier; public class PackDevCommand extends ClientCommandBase { static Minecraft mc = Minecraft.getMinecraft(); public PackDevCommand() { super("neupackdev"); } private static final HashMap> commands = new HashMap>() {{ put( "getnpc", new Command<>( "NPC", () -> mc.theWorld.playerEntities, true, AbstractClientPlayer.class ) ); put( "getnpcs", new Command<>( "NPC", () -> mc.theWorld.playerEntities, false, AbstractClientPlayer.class ) ); put( "getmob", new Command<>( "mob", () -> mc.theWorld.loadedEntityList, true, EntityLiving.class ) ); put( "getmobs", new Command<>( "mob", () -> mc.theWorld.loadedEntityList, false, EntityLiving.class ) ); put( "getarmorstand", new Command<>( "armor stand", () -> mc.theWorld.loadedEntityList, true, EntityArmorStand.class ) ); put( "getarmorstands", new Command<>( "armor stand", () -> mc.theWorld.loadedEntityList, false, EntityArmorStand.class ) ); }}; @Override public List addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) { return args.length == 1 ? getListOfStringsMatchingLastWord(args, commands.keySet()) : null; } public static void togglePackDeveloperMode(ICommandSender sender) { NotEnoughUpdates.INSTANCE.packDevEnabled = !NotEnoughUpdates.INSTANCE.packDevEnabled; if (NotEnoughUpdates.INSTANCE.packDevEnabled) { sender.addChatMessage(new ChatComponentText( EnumChatFormatting.GREEN + "Enabled pack developer mode.")); } else { sender.addChatMessage(new ChatComponentText( EnumChatFormatting.RED + "Disabled pack developer mode.")); } } @Override public void processCommand(ICommandSender sender, String[] args) throws CommandException { if (args.length == 0) { togglePackDeveloperMode(sender); return; } double dist = 5.0; if (args.length >= 2) { try { dist = Double.parseDouble(args[1]); } catch (NumberFormatException e) { sender.addChatMessage(new ChatComponentText( EnumChatFormatting.RED + "Invalid distance! Must be a number, defaulting to a radius of 5.")); } } StringBuilder output; String subCommand = args[0].toLowerCase(); if (commands.containsKey(subCommand)) { Command command = commands.get(subCommand); output = command.getData(dist); } else if (subCommand.equals("getall")) { output = getAll(dist); } else if (subCommand.equals("getallclose")) { output = getAllClose(dist); } else { sender.addChatMessage(new ChatComponentText( EnumChatFormatting.RED + "Invalid sub-command.")); return; } if (output.length() != 0) { MiscUtils.copyToClipboard(output.toString()); } } private static StringBuilder getAllClose(Double dist) { StringBuilder sb = new StringBuilder(); sb.append(commands.get("getmob").getData(dist)); sb.append(commands.get("getarmorstand").getData(dist)); sb.append(commands.get("getnpc").getData(dist)); return sb; } private static StringBuilder getAll(Double dist) { StringBuilder sb = new StringBuilder(); sb.append(commands.get("getmobs").getData(dist)); sb.append(commands.get("getarmorstands").getData(dist)); sb.append(commands.get("getnpcs").getData(dist)); return sb; } public static StringBuilder livingBaseDataBuilder(T entity, Class clazz) { StringBuilder entityData = new StringBuilder(); if (EntityPlayer.class.isAssignableFrom(entity.getClass())) { EntityPlayer entityPlayer = (EntityPlayer) entity; // NPC Information String skinResourcePath = ((AbstractClientPlayer) entityPlayer).getLocationSkin().getResourcePath(); entityData .append("Player Id: ") .append(entityPlayer.getUniqueID() != null ? entityPlayer.getUniqueID().toString() : "null") .append(entityPlayer.getCustomNameTag() != null ? entityPlayer.getCustomNameTag() : "null") .append("\nEntity Texture Id: ") .append(skinResourcePath != null ? skinResourcePath.replace("skins/", "") : "null"); } if (!clazz.isAssignableFrom(entity.getClass())) { return entityData; } //Entity Information entityData .append("Entity Id: ") .append(entity.getEntityId()) .append("\nMob: ") .append(entity.getName() != null ? entity.getName() : "null") .append("\nCustom Name: ") .append(entity.getCustomNameTag() != null ? entity.getCustomNameTag() : "null"); //Held Item if (entity.getHeldItem() != null) { entityData .append("\nItem: ") .append(entity.getHeldItem()) .append("\nItem Display Name: ") .append(entity.getHeldItem().getDisplayName() != null ? entity.getHeldItem().getDisplayName() : "null") .append("\nItem Tag Compound: "); NBTTagCompound heldItemTagCompound = entity.getHeldItem().getTagCompound(); if (heldItemTagCompound != null) { String heldItemString = heldItemTagCompound.toString(); NBTBase extraAttrTag = heldItemTagCompound.getTag("ExtraAttributes"); entityData .append(heldItemString != null ? heldItemString : "null") .append("\nItem Tag Compound Extra Attributes: ") .append(extraAttrTag != null ? extraAttrTag : "null"); } else { entityData.append("null"); } } else { entityData.append("\nItem: null"); } entityData.append(armorDataBuilder(entity)).append("\n\n"); return entityData; } private static final String[] armorPieceTypes = {"Boots", "Leggings", "Chestplate", "Helmet"}; public static StringBuilder armorDataBuilder(T entity) { StringBuilder armorData = new StringBuilder(); for (int i = 0; i < 4; i++) { ItemStack currentArmor = entity.getCurrentArmor(0); armorData.append(String.format("\n%s: ", armorPieceTypes[i])); if (currentArmor == null) { armorData.append("null"); } else { armorData.append(currentArmor.getTagCompound() != null ? currentArmor.getTagCompound().toString() : "null"); } } return armorData; } static class Command { String typeFriendlyName; Supplier> entitySupplier; Class clazz; boolean single; Command( String typeFriendlyName, Supplier> entitySupplier, boolean single, Class clazz ) { this.typeFriendlyName = typeFriendlyName; this.entitySupplier = entitySupplier; this.single = single; this.clazz = clazz; } @SuppressWarnings("unchecked") public StringBuilder getData(double dist) { StringBuilder result = new StringBuilder(); double distSq = dist * dist; T closest = null; for (Entity entity : entitySupplier.get()) { if (!clazz.isAssignableFrom(entity.getClass()) || entity == mc.thePlayer) { continue; } T entityT = (T) entity; double entityDistanceSq = entity.getDistanceSq(mc.thePlayer.posX, mc.thePlayer.posY, mc.thePlayer.posZ); if (entityDistanceSq < distSq) { if (single) { distSq = entityDistanceSq; closest = entityT; } else { result.append(livingBaseDataBuilder(entityT, clazz)); } } } if ((single && closest == null) || (!single && result.length() == 0)) { mc.thePlayer.addChatMessage(new ChatComponentText( EnumChatFormatting.RED + "No " + typeFriendlyName + "s found within " + dist + " blocks.")); } else { mc.thePlayer.addChatMessage(new ChatComponentText( EnumChatFormatting.GREEN + "Copied " + typeFriendlyName + " data to clipboard")); return single ? livingBaseDataBuilder(closest, clazz) : result; } return result; } } }