/* * KubaTech - Gregtech Addon * Copyright (C) 2022 kuba6000 * * 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; either * version 3 of the License, or (at your option) any later version. * * 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, see . * */ package kubatech.nei; import static kubatech.nei.Mob_Handler.Translations.*; import static org.lwjgl.opengl.GL11.GL_MODELVIEW_STACK_DEPTH; import codechicken.lib.gui.GuiDraw; import codechicken.nei.NEIClientUtils; import codechicken.nei.PositionedStack; import codechicken.nei.recipe.*; import cpw.mods.fml.common.event.FMLInterModComms; import crazypants.enderio.EnderIO; import crazypants.enderio.machine.spawner.BlockPoweredSpawner; import gregtech.api.util.GT_Utility; import java.awt.*; import java.lang.reflect.Field; import java.nio.FloatBuffer; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Random; import kubatech.api.LoaderReference; import kubatech.api.mobhandler.MobDrop; import kubatech.api.utils.FastRandom; import kubatech.api.utils.InfernalHelper; import kubatech.api.utils.MobUtils; import kubatech.api.utils.ModUtils; import kubatech.kubatech; import kubatech.loaders.MobRecipeLoader; import kubatech.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeExterminationChamber; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.gui.inventory.GuiInventory; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RendererLivingEntity; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLiving; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.StatCollector; import org.lwjgl.BufferUtils; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; public class Mob_Handler extends TemplateRecipeHandler { enum Translations { NORMAL_DROPS, RARE_DROPS, ADDITIONAL_DROPS, INFERNAL_DROPS, INFERNAL_CANNOT, INFERNAL_CAN, INFERNAL_ALWAYS, CHANCE, AVERAGE_REMINDER, MOD, MAX_HEALTH, LOOTABLE, PLAYER_ONLY, ; final String key; Translations() { key = "mobhandler." + this.name().toLowerCase(); } public String get() { return StatCollector.translateToLocal(key); } public String get(Object... args) { return StatCollector.translateToLocalFormatted(key, args); } public String getKey() { return key; } @Override public String toString() { return get(); } } private static final Mob_Handler instance = new Mob_Handler(); private static final List cachedRecipes = new ArrayList<>(); public static int cycleTicksStatic = Math.abs((int) System.currentTimeMillis()); private static final int itemsPerRow = 8, itemXShift = 18, itemYShift = 18, nextRowYShift = 35; public static void addRecipe(EntityLiving e, List drop) { List positionedStacks = new ArrayList<>(); int xorigin = 7, xoffset = xorigin, yoffset = 95, normaldrops = 0, raredrops = 0, additionaldrops = 0, infernaldrops = 0; MobDrop.DropType i = null; for (MobDrop d : drop) { if (i == d.type) { xoffset += itemXShift; if (xoffset >= xorigin + (itemXShift * itemsPerRow)) { xoffset = xorigin; yoffset += itemYShift; } } if (i != null && i != d.type) { xoffset = xorigin; yoffset += nextRowYShift; } i = d.type; if (d.type == MobDrop.DropType.Normal) normaldrops++; else if (d.type == MobDrop.DropType.Rare) raredrops++; else if (d.type == MobDrop.DropType.Additional) additionaldrops++; else if (d.type == MobDrop.DropType.Infernal) break; // dont render infernal drops positionedStacks.add(new MobPositionedStack( d.stack.copy(), xoffset, yoffset, d.type, d.chance, d.enchantable, d.damages != null ? new ArrayList<>(d.damages.keySet()) : null, d.lootable, d.playerOnly)); } instance.addRecipeInt(e, positionedStacks, normaldrops, raredrops, additionaldrops, infernaldrops); } private void addRecipeInt( EntityLiving e, List l, int normaldrops, int raredrops, int additionaldrops, int infernalDrops) { cachedRecipes.add(new MobCachedRecipe(e, l, normaldrops, raredrops, additionaldrops, infernalDrops)); } public static void clearRecipes() { cachedRecipes.clear(); } public static void sortCachedRecipes() { cachedRecipes.sort((o1, o2) -> { boolean m1 = o1.mod.equals("Minecraft"); boolean m2 = o2.mod.equals("Minecraft"); if (m1 && !m2) return -1; else if (!m1 && m2) return 1; if (!o1.mod.equals(o2.mod)) return o1.mod.compareTo(o2.mod); else return o1.localizedName.compareTo(o2.localizedName); }); } public Mob_Handler() { this.transferRects.add(new RecipeTransferRect(new Rectangle(7, 62, 16, 16), getOverlayIdentifier())); if (!NEI_Config.isAdded) { FMLInterModComms.sendRuntimeMessage( kubatech.instance, "NEIPlugins", "register-crafting-handler", "kubatech@" + getRecipeName() + "@" + getOverlayIdentifier()); GuiCraftingRecipe.craftinghandlers.add(this); GuiUsageRecipe.usagehandlers.add(this); } } @Override public TemplateRecipeHandler newInstance() { return new Mob_Handler(); } @Override public String getOverlayIdentifier() { return "kubatech.mobhandler"; } @Override public String getGuiTexture() { return "kubatech:textures/gui/MobHandler.png"; } private static final Field mainmodelfield; static { try { mainmodelfield = RendererLivingEntity.class.getDeclaredField( ModUtils.isDeobfuscatedEnvironment ? "mainModel" : "field_77045_g"); mainmodelfield.setAccessible(true); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } } @Override public void drawBackground(int recipe) { GL11.glColor4f(1f, 1f, 1f, 1f); GuiDraw.changeTexture(getGuiTexture()); GuiDraw.drawTexturedModalRect(0, 0, 0, 0, 168, 192); MobCachedRecipe currentrecipe = ((MobCachedRecipe) arecipes.get(recipe)); { int x = 6, y = 94, yshift = nextRowYShift; if (currentrecipe.normalOutputsCount > 0) { for (int i = 0; i < ((currentrecipe.normalOutputsCount - 1) / itemsPerRow) + 1; i++) { GuiDraw.drawTexturedModalRect(x, y + (18 * i), 0, 192, 144, 18); if (i > 0) GuiDraw.drawTexturedModalRect(x, y + ((18 * i) - 1), 0, 193, 144, 2); } y += yshift + ((currentrecipe.normalOutputsCount - 1) / itemsPerRow) * 18; } if (currentrecipe.rareOutputsCount > 0) { for (int i = 0; i < ((currentrecipe.rareOutputsCount - 1) / itemsPerRow) + 1; i++) { GuiDraw.drawTexturedModalRect(x, y + (18 * i), 0, 192, 144, 18); if (i > 0) GuiDraw.drawTexturedModalRect(x, y + ((18 * i) - 1), 0, 193, 144, 2); } y += yshift + ((currentrecipe.rareOutputsCount - 1) / itemsPerRow) * 18; } if (currentrecipe.additionalOutputsCount > 0) { for (int i = 0; i < ((currentrecipe.additionalOutputsCount - 1) / itemsPerRow) + 1; i++) { GuiDraw.drawTexturedModalRect(x, y + (18 * i), 0, 192, 144, 18); if (i > 0) GuiDraw.drawTexturedModalRect(x, y + ((18 * i) - 1), 0, 193, 144, 2); } y += yshift + ((currentrecipe.additionalOutputsCount - 1) / itemsPerRow) * 18; } if (currentrecipe.infernalOutputsCount > 0) { for (int i = 0; i < ((currentrecipe.infernalOutputsCount - 1) / itemsPerRow) + 1; i++) { GuiDraw.drawTexturedModalRect(x, y + (18 * i), 0, 192, 144, 18); if (i > 0) GuiDraw.drawTexturedModalRect(x, y + ((18 * i) - 1), 0, 193, 144, 2); } } } GL11.glEnable(GL11.GL_DEPTH_TEST); GL11.glColor4f(1f, 1f, 1f, 1f); Minecraft mc = Minecraft.getMinecraft(); ScaledResolution scale = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); int width = scale.getScaledWidth(); int height = scale.getScaledHeight(); int mouseX = Mouse.getX() * width / mc.displayWidth; int mouseZ = height - Mouse.getY() * height / mc.displayHeight - 1; // Get current x,y from matrix FloatBuffer buf = BufferUtils.createFloatBuffer(16); GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, buf); float x = buf.get(12); float y = buf.get(13); int stackdepth = GL11.glGetInteger(GL_MODELVIEW_STACK_DEPTH); GL11.glPushMatrix(); try { EntityLiving e = currentrecipe.mob; float eheight = MobUtils.getMobHeight(e); float scaled = MobUtils.getDesiredScale(eheight, 27); // // int maxwidth = 15; // scaled = (int) Math.min(scaled, maxwidth / ewidth); int mobx = 30, moby = 50; e.setPosition(mc.thePlayer.posX + 5, mc.thePlayer.posY, mc.thePlayer.posZ); // ARGS: x, y, scale, rot, rot, entity GuiInventory.func_147046_a( mobx, moby, Math.round(scaled), (float) (x + mobx) - mouseX, (float) (y + moby - eheight * scaled) - mouseZ, e); } catch (Throwable ex) { Tessellator tes = Tessellator.instance; try { tes.draw(); } catch (Exception ignored) { } } stackdepth -= GL11.glGetInteger(GL_MODELVIEW_STACK_DEPTH); if (stackdepth < 0) for (; stackdepth < 0; stackdepth++) GL11.glPopMatrix(); GL11.glDisable(GL11.GL_DEPTH_TEST); } @Override public void drawForeground(int recipe) { MobCachedRecipe currentrecipe = ((MobCachedRecipe) arecipes.get(recipe)); int y = 7, yshift = 10, x = 57; GuiDraw.drawString(currentrecipe.localizedName, x, y, 0xFF555555, false); if (Minecraft.getMinecraft().gameSettings.advancedItemTooltips && NEIClientUtils.shiftKey()) GuiDraw.drawString(currentrecipe.mobname, x, y += yshift, 0xFF555555, false); GuiDraw.drawString(MOD.get() + currentrecipe.mod, x, y += yshift, 0xFF555555, false); GuiDraw.drawString(MAX_HEALTH.get() + currentrecipe.maxHealth, x, y += yshift, 0xFF555555, false); switch (currentrecipe.infernaltype) { case -1: break; case 0: GuiDraw.drawString(INFERNAL_CANNOT.get(), x, y += yshift, 0xFF555555, false); break; case 1: GuiDraw.drawString(INFERNAL_CAN.get(), x, y += yshift, 0xFFFF0000, false); break; case 2: GuiDraw.drawString(INFERNAL_ALWAYS.get(), x, y += yshift, 0xFFFF0000, false); break; } MobRecipeLoader.MobRecipe MBRecipe = GT_MetaTileEntity_ExtremeExterminationChamber.MobNameToRecipeMap.get(currentrecipe.mobname); if (MBRecipe != null) { GuiDraw.drawString( GT_Utility.trans("153", "Usage: ") + GT_Utility.formatNumbers(MBRecipe.mEUt) + " EU/t", x, y += yshift, 0xFF555555, false); GuiDraw.drawString( GT_Utility.trans("158", "Time: ") + GT_Utility.formatNumbers(MBRecipe.mDuration / 20d) + " secs", x, y += yshift, 0xFF555555, false); } x = 6; y = 83; yshift = nextRowYShift; if (currentrecipe.normalOutputsCount > 0) { GuiDraw.drawString(NORMAL_DROPS.get(), x, y, 0xFF555555, false); y += yshift + ((currentrecipe.normalOutputsCount - 1) / itemsPerRow) * 18; } if (currentrecipe.rareOutputsCount > 0) { GuiDraw.drawString(RARE_DROPS.get(), x, y, 0xFF555555, false); y += yshift + ((currentrecipe.rareOutputsCount - 1) / itemsPerRow) * 18; } if (currentrecipe.additionalOutputsCount > 0) { GuiDraw.drawString(ADDITIONAL_DROPS.get(), x, y, 0xFF555555, false); y += yshift + ((currentrecipe.additionalOutputsCount - 1) / itemsPerRow) * 18; } if (currentrecipe.infernalOutputsCount > 0) { GuiDraw.drawString(INFERNAL_DROPS.get(), x, y, 0xFF555555, false); y += yshift + ((currentrecipe.additionalOutputsCount - 1) / itemsPerRow) * 18; } yshift = 10; } @Override public String getRecipeName() { return "Mob Drops"; } @Override public IUsageHandler getUsageAndCatalystHandler(String inputId, Object... ingredients) { if (inputId.equals("item")) { TemplateRecipeHandler handler = newInstance(); ItemStack candidate = (ItemStack) ingredients[0]; if (RecipeCatalysts.containsCatalyst(handler, candidate)) { handler.loadCraftingRecipes(getOverlayIdentifier(), (Object) null); return handler; } } return this.getUsageHandler(inputId, ingredients); } @Override public void loadCraftingRecipes(String outputId, Object... results) { if (outputId.equals(getOverlayIdentifier())) { arecipes.addAll(cachedRecipes); return; } super.loadCraftingRecipes(outputId, results); } @Override public void loadCraftingRecipes(ItemStack result) { for (MobCachedRecipe r : cachedRecipes) if (r.contains(r.mOutputs, result)) arecipes.add(r); } @Override public void loadUsageRecipes(ItemStack ingredient) { if (LoaderReference.EnderIO && ingredient.getItem() == Item.getItemFromBlock(EnderIO.blockPoweredSpawner)) { if (!ingredient.hasTagCompound() || !ingredient.getTagCompound().hasKey("mobType")) { loadCraftingRecipes(getOverlayIdentifier(), (Object) null); return; } for (MobCachedRecipe r : cachedRecipes) if (r.mInput.stream() .anyMatch(s -> s.getItem() == ingredient.getItem() && Objects.equals( s.getTagCompound().getString("mobType"), ingredient.getTagCompound().getString("mobType")))) arecipes.add(r); } else for (MobCachedRecipe r : cachedRecipes) if (r.mInput.stream().anyMatch(ingredient::isItemEqual)) arecipes.add(r); } @Override public void onUpdate() { cycleTicksStatic++; } public static class MobPositionedStack extends PositionedStack { public final MobDrop.DropType type; public final int chance; public final boolean enchantable; public final boolean randomdamage; public final List damages; public final int enchantmentLevel; private final Random rand; public MobPositionedStack( Object object, int x, int y, MobDrop.DropType type, int chance, Integer enchantable, List damages, boolean lootable, boolean isPlayerOnly) { super(object, x, y, false); rand = new FastRandom(); this.type = type; this.chance = chance; this.enchantable = enchantable != null; if (this.enchantable) enchantmentLevel = enchantable; else enchantmentLevel = 0; this.randomdamage = damages != null; if (this.randomdamage) this.damages = damages; else this.damages = null; NBTTagList extratooltip = new NBTTagList(); if (chance != 10000) extratooltip.appendTag(new NBTTagString( EnumChatFormatting.RESET + CHANCE.get() + (chance / 100) + "." + (chance % 100) + "%")); if (lootable) extratooltip.appendTag(new NBTTagString(EnumChatFormatting.RESET + LOOTABLE.get())); if (isPlayerOnly) extratooltip.appendTag(new NBTTagString(EnumChatFormatting.RESET + PLAYER_ONLY.get())); extratooltip.appendTag(new NBTTagString(EnumChatFormatting.RESET + AVERAGE_REMINDER.get())); NBTTagCompound itemtag = this.items[0].getTagCompound(); if (itemtag == null) itemtag = new NBTTagCompound(); NBTTagCompound display = new NBTTagCompound(); if (itemtag.hasKey("display")) { display = itemtag.getCompoundTag("display"); if (display.hasKey("Lore")) { NBTTagList lore = display.getTagList("Lore", 8); for (int i = 0; i < extratooltip.tagCount(); i++) lore.appendTag(new NBTTagString(extratooltip.getStringTagAt(i))); display.setTag("Lore", lore); } else display.setTag("Lore", extratooltip); } else display.setTag("Lore", extratooltip); itemtag.setTag("display", display); this.items[0].setTagCompound(itemtag); this.item.setTagCompound((NBTTagCompound) itemtag.copy()); setPermutationToRender(0); } @Override public void setPermutationToRender(int index) { if (this.item == null) this.item = this.items[0].copy(); if (enchantable) { if (this.item.getItem() == Items.enchanted_book) this.item = this.items[0].copy(); this.item.getTagCompound().removeTag("ench"); EnchantmentHelper.addRandomEnchantment(rand, this.item, enchantmentLevel); } if (randomdamage) this.item.setItemDamage(damages.get(rand.nextInt(damages.size()))); } } private class MobCachedRecipe extends TemplateRecipeHandler.CachedRecipe { public final EntityLiving mob; public final List mOutputs; public final List mInput; public final String mobname; public final int infernaltype; public final PositionedStack ingredient; public final String localizedName; public final String mod; public final float maxHealth; public final int normalOutputsCount; public final int rareOutputsCount; public final int additionalOutputsCount; public final int infernalOutputsCount; public MobCachedRecipe( EntityLiving mob, List mOutputs, int normalOutputsCount, int rareOutputsCount, int additionalOutputsCount, int infernalOutputsCount) { super(); String classname = mob.getClass().getName(); this.mod = ModUtils.getModNameFromClassName(classname); this.mob = mob; this.maxHealth = mob.getMaxHealth(); this.mOutputs = new ArrayList<>(mOutputs.size()); this.mOutputs.addAll(mOutputs); this.normalOutputsCount = normalOutputsCount; this.rareOutputsCount = rareOutputsCount; this.additionalOutputsCount = additionalOutputsCount; this.infernalOutputsCount = infernalOutputsCount; this.mInput = new ArrayList<>(); int id = EntityList.getEntityID(mob); mobname = EntityList.getEntityString(mob); localizedName = StatCollector.translateToLocal("entity." + mobname + ".name"); if (id != 0) { this.mInput.add(new ItemStack(Items.spawn_egg, 1, id)); this.mInput.add(new ItemStack(Blocks.mob_spawner, 1, id)); } if (LoaderReference.EnderIO) { ItemStack s = new ItemStack(EnderIO.blockPoweredSpawner, 1); NBTTagCompound nbt = new NBTTagCompound(); BlockPoweredSpawner.writeMobTypeToNBT(nbt, mobname); s.setTagCompound(nbt); this.mInput.add(0, s); } else if (id == 0) this.mInput.add(new ItemStack(Items.spawn_egg, 1, 0)); // ??? ingredient = new PositionedStack(this.mInput.get(0), 38, 44, false); if (!LoaderReference.InfernalMobs) infernaltype = -1; // not supported else { if (!InfernalHelper.isClassAllowed(mob)) infernaltype = 0; // not allowed else if (InfernalHelper.checkEntityClassForced(mob)) infernaltype = 2; // forced else infernaltype = 1; // normal } } @Override public PositionedStack getIngredient() { return ingredient; } @Override public PositionedStack getResult() { return null; } @Override public List getOtherStacks() { if (cycleTicksStatic % 10 == 0) mOutputs.forEach(p -> p.setPermutationToRender(0)); return mOutputs; } } }