aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de/cowtipper/cowlection/handler/AnalyzeIslandTracker.java
diff options
context:
space:
mode:
authorCow <cow@volloeko.de>2022-10-23 13:26:42 +0200
committerCow <cow@volloeko.de>2022-10-23 13:26:42 +0200
commitc091d26e534ab51a3d4f2ed3c4f285f4c318aeee (patch)
tree96e6b495d7b289da7cbf0578b6df4ffbaaea7b0c /src/main/java/de/cowtipper/cowlection/handler/AnalyzeIslandTracker.java
parentfeea22f251cd188d91b843ff9348e057e0f9e91d (diff)
downloadCowlection-c091d26e534ab51a3d4f2ed3c4f285f4c318aeee.tar.gz
Cowlection-c091d26e534ab51a3d4f2ed3c4f285f4c318aeee.tar.bz2
Cowlection-c091d26e534ab51a3d4f2ed3c4f285f4c318aeee.zip
Added accumulating results for `/moo analyzeIsland`
Diffstat (limited to 'src/main/java/de/cowtipper/cowlection/handler/AnalyzeIslandTracker.java')
-rw-r--r--src/main/java/de/cowtipper/cowlection/handler/AnalyzeIslandTracker.java186
1 files changed, 186 insertions, 0 deletions
diff --git a/src/main/java/de/cowtipper/cowlection/handler/AnalyzeIslandTracker.java b/src/main/java/de/cowtipper/cowlection/handler/AnalyzeIslandTracker.java
new file mode 100644
index 0000000..2dcaa60
--- /dev/null
+++ b/src/main/java/de/cowtipper/cowlection/handler/AnalyzeIslandTracker.java
@@ -0,0 +1,186 @@
+package de.cowtipper.cowlection.handler;
+
+import de.cowtipper.cowlection.Cowlection;
+import de.cowtipper.cowlection.config.MooConfig;
+import de.cowtipper.cowlection.data.DataHelper;
+import de.cowtipper.cowlection.util.ImageUtils;
+import de.cowtipper.cowlection.util.MooChatComponent;
+import de.cowtipper.cowlection.util.Utils;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.item.ItemSkull;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.tileentity.TileEntityChest;
+import net.minecraft.tileentity.TileEntityHopper;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.world.World;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.common.util.Constants;
+import net.minecraftforge.event.entity.player.PlayerSetSpawnEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class AnalyzeIslandTracker {
+ private static final String MINION_WITH_SKIN = EnumChatFormatting.RED + "Unknown minion " + EnumChatFormatting.YELLOW + "(new or with minion skin)";
+ private final Map<BlockPos, DataHelper.Minion> minions;
+ private int minionsWithSkinCount;
+ private final Set<BlockPos> chests;
+ private final Set<BlockPos> hoppers;
+ private Map<String, DataHelper.Minion> minionsDatabase;
+ private final Cowlection main;
+
+ public AnalyzeIslandTracker(Cowlection main) {
+ this.main = main;
+ minions = new HashMap<>();
+ chests = new HashSet<>();
+ hoppers = new HashSet<>();
+ minionsWithSkinCount = 0;
+ }
+
+ @SubscribeEvent
+ public void onWorldEnter(PlayerSetSpawnEvent e) {
+ MinecraftForge.EVENT_BUS.unregister(this);
+ minions.clear();
+ chests.clear();
+ hoppers.clear();
+ minionsWithSkinCount = 0;
+ minionsDatabase = null;
+ }
+
+ public void analyzeIsland(World world) {
+ MinecraftForge.EVENT_BUS.register(this);
+
+ boolean isInitialSearch = false;
+ if (minionsDatabase == null) {
+ minionsDatabase = DataHelper.getMinions();
+ isInitialSearch = true;
+ }
+
+ int previousMinionCount = minions.size();
+ int previousMinionWithSkinCount = minionsWithSkinCount;
+ int previousChestCount = chests.size();
+ int previousHopperCount = hoppers.size();
+
+ entityLoop:
+ for (Entity entity : world.loadedEntityList) {
+ if (!(entity instanceof EntityArmorStand)) {
+ continue;
+ }
+ EntityArmorStand minion = (EntityArmorStand) entity;
+
+ if (minion.isInvisible() || !minion.isSmall() || minion.getHeldItem() == null) {
+ // not a minion: invisible, or not small armor stand, or no item in hand (= minion in a minion chair)
+ continue;
+ }
+ for (int slot = 0; slot < 4; slot++) {
+ if (minion.getCurrentArmor(slot) == null) {
+ // not a minion: missing equipment
+ continue entityLoop;
+ }
+ }
+ ItemStack skullItem = minion.getCurrentArmor(3); // head slot
+ if (skullItem.getItem() instanceof ItemSkull && skullItem.getMetadata() == 3 && skullItem.hasTagCompound()) {
+ // is a player head!
+ if (skullItem.getTagCompound().hasKey("SkullOwner", Constants.NBT.TAG_COMPOUND)) {
+ NBTTagCompound skullOwner = skullItem.getTagCompound().getCompoundTag("SkullOwner");
+ String skullDataBase64 = skullOwner.getCompoundTag("Properties").getTagList("textures", Constants.NBT.TAG_COMPOUND).getCompoundTagAt(0).getString("Value");
+ String skullData = new String(Base64.decodeBase64(skullDataBase64));
+ String minionSkinId = StringUtils.substringBetween(skullData, "http://textures.minecraft.net/texture/", "\"");
+ DataHelper.Minion detectedMinion = minionsDatabase.get(minionSkinId);
+ if (detectedMinion != null) {
+ // minion head matches one know minion tier
+ this.minions.put(minion.getPosition(), detectedMinion);
+ } else {
+ int minionTier = ImageUtils.getTierFromTexture(minionSkinId);
+ if (minionTier > 0) {
+ DataHelper.Minion overwrittenMinion = this.minions.put(minion.getPosition(), new DataHelper.Minion(MINION_WITH_SKIN, minionTier));
+ if (overwrittenMinion == null || !MINION_WITH_SKIN.equals(overwrittenMinion.getType())) {
+ ++minionsWithSkinCount;
+ }
+ } else {
+ // looked like a minion but has no matching tier badge
+ main.getLogger().info("[/moo analyzeIsland] Found an armor stand that could be a minion but it is missing a tier badge: " + minionSkinId + "\t\t\t" + minion.serializeNBT());
+ }
+ }
+ }
+ }
+ }
+
+ // Tile entities (chests/hoppers)
+ for (TileEntity tileEntity : world.loadedTileEntityList) {
+ if (tileEntity instanceof TileEntityChest) {
+ this.chests.add(tileEntity.getPos());
+ } else if (tileEntity instanceof TileEntityHopper) {
+ this.hoppers.add(tileEntity.getPos());
+ }
+ }
+ sendAnalysisReport();
+
+ if (isInitialSearch) {
+ main.getChatHelper().sendMessage(new MooChatComponent(" (repeat the command in other areas to scan them as well)").lightPurple().setSuggestCommand("/moo analyzeIsland"));
+ } else {
+ StringBuilder newlyFound = new StringBuilder(" (");
+ int minionDiff = minions.size() - previousMinionCount;
+ int chestDiff = chests.size() - previousChestCount;
+ int hopperDiff = hoppers.size() - previousHopperCount;
+ if (minionDiff > 0) {
+ newlyFound.append("+").append(minionDiff).append(" Minions ");
+
+ int minionWithSkinDiff = minionsWithSkinCount - previousMinionWithSkinCount;
+ if (minionWithSkinDiff > 0) {
+ newlyFound.append("[+").append(minionWithSkinDiff).append(" with skins] ");
+ }
+ }
+ if (chestDiff > 0) {
+ newlyFound.append("+").append(chestDiff).append(" Chests ");
+ }
+ if (hopperDiff > 0) {
+ newlyFound.append("+").append(hopperDiff).append(" Hoppers ");
+ }
+
+ if (newlyFound.length() > 5) {
+ main.getChatHelper().sendMessage(EnumChatFormatting.GRAY, newlyFound.append("compared to previous scan)").toString());
+ } else {
+ main.getChatHelper().sendMessage(EnumChatFormatting.GRAY, " (= same as previous scan)");
+ }
+ }
+ }
+
+ private void sendAnalysisReport() {
+ StringBuilder analysisResults = new StringBuilder("Found ").append(EnumChatFormatting.GOLD).append(this.minions.size()).append(EnumChatFormatting.YELLOW).append(" minions");
+ if (minionsWithSkinCount > 0) {
+ analysisResults.append(" (").append(EnumChatFormatting.GOLD).append(minionsWithSkinCount).append(EnumChatFormatting.YELLOW).append(" unknown minions)");
+ }
+ analysisResults.append(" nearby");
+ this.minions.values().stream()
+ .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
+ .entrySet().stream()
+ .sorted(Map.Entry.comparingByKey()) // sort alphabetically by minion type and tier
+ .forEach(minionEntry -> {
+ DataHelper.Minion minion = minionEntry.getKey();
+ long occurrences = minionEntry.getValue();
+
+ analysisResults.append("\n ").append(EnumChatFormatting.GOLD).append(occurrences).append(occurrences > 1 ? "✕ " : "⨉ ")
+ .append(EnumChatFormatting.YELLOW).append(minion.getType())
+ .append(" ")
+ .append(Utils.getMinionTierColor(minion.getTier())).append(MooConfig.useRomanNumerals() ? Utils.convertArabicToRoman(minion.getTier()) : minion.getTier());
+ });
+
+ analysisResults.append("\n").append(EnumChatFormatting.YELLOW).append("Found ")
+ .append(EnumChatFormatting.GOLD).append(chests.size()).append(EnumChatFormatting.YELLOW).append(" chests and ")
+ .append(EnumChatFormatting.GOLD).append(hoppers.size()).append(EnumChatFormatting.YELLOW).append(" hoppers nearby.");
+
+ main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, analysisResults.toString());
+ }
+}