diff options
author | Jakub <53441451+kuba6000@users.noreply.github.com> | 2022-08-14 15:19:13 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-14 15:19:13 +0200 |
commit | 6d436a2c6a5d9b51070b8399c4fdb196603a8e82 (patch) | |
tree | 0ac08abe69626ad89e25eb9b0c7aadb7e5243dac /src/main/java/kubatech/loaders/MobRecipeLoader.java | |
parent | d8d8a462a25a29a9640f6c038ced50a570255e6e (diff) | |
download | GT5-Unofficial-6d436a2c6a5d9b51070b8399c4fdb196603a8e82.tar.gz GT5-Unofficial-6d436a2c6a5d9b51070b8399c4fdb196603a8e82.tar.bz2 GT5-Unofficial-6d436a2c6a5d9b51070b8399c4fdb196603a8e82.zip |
Add "Mob Drops" NEI page + Extreme Extermination Chamber (#1)
* First commit
* Mixins
* Merge the same items with diffrent damage
* Faster random in NEI
* More accuracy ?
* Update ClientProxy.java
* Renaming
* Update buildscript
* Use reserved MTE ID's
* EEC work
* Rework NEI page
* Fix inaccurate chances
* Basic equipment spawn
* Add config options
* Translations
* Add infernal drops
* Witchery fix
* Forestry fixes
* More fixes
* Default blacklist
* NEI sorting
* Comment out testing deps
* Clientsided check
* Blood Magic support
* LoaderReference
* Check if peacefull is allowed
* Add some XP output
* Add recipe
* Send Server config to Client
* Add command to reload config
* Translations
* Process MT additions
Diffstat (limited to 'src/main/java/kubatech/loaders/MobRecipeLoader.java')
-rw-r--r-- | src/main/java/kubatech/loaders/MobRecipeLoader.java | 973 |
1 files changed, 973 insertions, 0 deletions
diff --git a/src/main/java/kubatech/loaders/MobRecipeLoader.java b/src/main/java/kubatech/loaders/MobRecipeLoader.java new file mode 100644 index 0000000000..033beb49fd --- /dev/null +++ b/src/main/java/kubatech/loaders/MobRecipeLoader.java @@ -0,0 +1,973 @@ +/* + * KubaTech - Gregtech Addon + * Copyright (C) 2022 kuba6000 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +package kubatech.loaders; + +import static kubatech.api.utils.ModUtils.isClientSided; +import static kubatech.api.utils.ModUtils.isDeobfuscatedEnvironment; +import static kubatech.common.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeExterminationChamber.MobNameToRecipeMap; + +import atomicstryker.infernalmobs.common.InfernalMobsCore; +import atomicstryker.infernalmobs.common.MobModifier; +import atomicstryker.infernalmobs.common.mods.api.ModifierLoader; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.util.GT_Utility; +import gregtech.common.GT_DummyWorld; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.stream.Collectors; +import kubatech.Config; +import kubatech.Tags; +import kubatech.api.LoaderReference; +import kubatech.api.utils.InfernalHelper; +import kubatech.common.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeExterminationChamber; +import kubatech.nei.Mob_Handler; +import kubatech.network.LoadConfigPacket; +import minetweaker.MineTweakerAPI; +import minetweaker.api.entity.IEntityDefinition; +import minetweaker.api.item.IItemStack; +import minetweaker.mc1710.item.MCItemStack; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.monster.EntitySlime; +import net.minecraft.entity.monster.IMob; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.client.event.GuiOpenEvent; +import net.minecraftforge.common.MinecraftForge; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import stanhebben.zenscript.value.IntRange; +import thaumcraft.common.items.wands.ItemWandCasting; + +public class MobRecipeLoader { + + private static final Logger LOG = LogManager.getLogger(Tags.MODID + "[Mob Handler]"); + + public static final MobRecipeLoader instance = new MobRecipeLoader(); + + @SuppressWarnings("unused") + @SubscribeEvent + public void onOpenGui(GuiOpenEvent event) { + MobRecipeLoader.generateMobRecipeMap(); + MinecraftForge.EVENT_BUS.unregister(instance); + } + + private static final String dropFewItemsName = isDeobfuscatedEnvironment ? "dropFewItems" : "func_70628_a"; + private static final String dropRareDropName = isDeobfuscatedEnvironment ? "dropRareDrop" : "func_70600_l"; + private static final String setSlimeSizeName = isDeobfuscatedEnvironment ? "setSlimeSize" : "func_70799_a"; + private static final String addRandomArmorName = isDeobfuscatedEnvironment ? "addRandomArmor" : "func_82164_bB"; + private static final String enchantEquipmentName = isDeobfuscatedEnvironment ? "enchantEquipment" : "func_82162_bC"; + private static final String randName = isDeobfuscatedEnvironment ? "rand" : "field_70146_Z"; + + private static boolean alreadyGenerated = false; + public static boolean isInGenerationProcess = false; + public static final String randomEnchantmentDetectedString = "RandomEnchantmentDetected"; + + public static class MobRecipe { + public final ArrayList<MobDrop> mOutputs; + public final int mEUt = 2000; + public final int mDuration; + public final int mMaxDamageChance; + public final boolean infernalityAllowed; + public final boolean alwaysinfernal; + public static droplist infernaldrops; + public final boolean isPeacefulAllowed; + + @SuppressWarnings("unchecked") + public MobRecipe copy() { + return new MobRecipe( + (ArrayList<MobDrop>) mOutputs.clone(), + mDuration, + mMaxDamageChance, + infernalityAllowed, + alwaysinfernal, + isPeacefulAllowed); + } + + private MobRecipe( + ArrayList<MobDrop> mOutputs, + int mDuration, + int mMaxDamageChance, + boolean infernalityAllowed, + boolean alwaysinfernal, + boolean isPeacefulAllowed) { + this.mOutputs = mOutputs; + this.mDuration = mDuration; + this.mMaxDamageChance = mMaxDamageChance; + this.infernalityAllowed = infernalityAllowed; + this.alwaysinfernal = alwaysinfernal; + this.isPeacefulAllowed = isPeacefulAllowed; + } + + @SuppressWarnings("unchecked") + public MobRecipe(EntityLiving e, ArrayList<MobDrop> outputs) { + if (infernaldrops == null && LoaderReference.InfernalMobs) { + infernaldrops = new droplist(); + LOG.info("Generating Infernal drops"); + ArrayList<ModifierLoader<?>> modifierLoaders = (ArrayList<ModifierLoader<?>>) + InfernalHelper.getModifierLoaders().clone(); + int i = 0; + for (ModifierLoader<?> modifierLoader : modifierLoaders) { + MobModifier nextMod = modifierLoader.make(null); + if (nextMod.getBlackListMobClasses() != null) + for (Class<?> cl : nextMod.getBlackListMobClasses()) + if (e.getClass().isAssignableFrom(cl)) break; + i++; + } + if (i > 0) { + double chance = + InfernalHelper.checkEntityClassForced(e) ? 1d : (1d / InfernalHelper.getEliteRarity()); + ArrayList<ItemStack> elitelist = InfernalHelper.getDropIdListElite(); + for (ItemStack stack : elitelist) { + dropinstance instance = infernaldrops.add( + new dropinstance(stack.copy(), infernaldrops), chance / elitelist.size()); + instance.isEnchatmentRandomized = true; + instance.enchantmentLevel = stack.getItem().getItemEnchantability(); + } + ArrayList<ItemStack> ultralist = InfernalHelper.getDropIdListUltra(); + chance *= 1d / InfernalHelper.getUltraRarity(); + for (ItemStack stack : ultralist) { + dropinstance instance = infernaldrops.add( + new dropinstance(stack.copy(), infernaldrops), chance / ultralist.size()); + instance.isEnchatmentRandomized = true; + instance.enchantmentLevel = stack.getItem().getItemEnchantability(); + } + ArrayList<ItemStack> infernallist = InfernalHelper.getDropIdListInfernal(); + chance *= 1d / InfernalHelper.getInfernoRarity(); + for (ItemStack stack : infernallist) { + dropinstance instance = infernaldrops.add( + new dropinstance(stack.copy(), infernaldrops), chance / infernallist.size()); + instance.isEnchatmentRandomized = true; + instance.enchantmentLevel = stack.getItem().getItemEnchantability(); + } + } + } else if (infernaldrops == null) infernaldrops = new droplist(); + + infernalityAllowed = InfernalHelper.isClassAllowed(e); + alwaysinfernal = InfernalHelper.checkEntityClassForced(e); + isPeacefulAllowed = !(e instanceof IMob); + + mOutputs = outputs; + int maxdamagechance = 0; + for (MobDrop o : mOutputs) { + if (o.damages != null) for (int v : o.damages.values()) maxdamagechance += v; + } + mMaxDamageChance = maxdamagechance; + // Powered spawner with octadic capacitor spawns ~22/min ~= 0.366/sec ~= 2.72s/spawn ~= 54.54t/spawn + mDuration = 55 + 10 + (((int) e.getMaxHealth() / 5) * 10); + } + + public ItemStack[] generateOutputs(Random rnd, GT_MetaTileEntity_ExtremeExterminationChamber MTE) { + MTE.mEUt = mEUt; + MTE.mMaxProgresstime = mDuration; + ArrayList<ItemStack> stacks = new ArrayList<>(mOutputs.size()); + for (MobDrop o : mOutputs) { + if (o.chance == 10000 || rnd.nextInt(10000) < o.chance) { + ItemStack s = o.stack.copy(); + if (o.enchantable != null) EnchantmentHelper.addRandomEnchantment(rnd, s, o.enchantable); + if (o.damages != null) { + int rChance = rnd.nextInt(mMaxDamageChance); + int cChance = 0; + for (Map.Entry<Integer, Integer> damage : o.damages.entrySet()) { + cChance += damage.getValue(); + if (rChance <= cChance) { + s.setItemDamage(damage.getKey()); + break; + } + } + } + stacks.add(s); + } + } + + if (infernalityAllowed + && mEUt * 8 < MTE.getMaxInputVoltage() + && !InfernalHelper.getDimensionBlackList() + .contains(MTE.getBaseMetaTileEntity().getWorld().provider.dimensionId)) { + int p = 0; + int mods = 0; + if (alwaysinfernal || rnd.nextInt(InfernalHelper.getEliteRarity()) == 0) { + p = 1; + if (rnd.nextInt(InfernalHelper.getUltraRarity()) == 0) { + p = 2; + if (rnd.nextInt(InfernalHelper.getInfernoRarity()) == 0) p = 3; + } + } + ArrayList<ItemStack> infernalstacks = null; + if (p > 0) + if (p == 1) { + infernalstacks = InfernalHelper.getDropIdListElite(); + mods = InfernalHelper.getMinEliteModifiers(); + } else if (p == 2) { + infernalstacks = InfernalHelper.getDropIdListUltra(); + mods = InfernalHelper.getMinUltraModifiers(); + } else if (p == 3) { + infernalstacks = InfernalHelper.getDropIdListInfernal(); + mods = InfernalHelper.getMinInfernoModifiers(); + } + if (infernalstacks != null) { + ItemStack infernalstack = infernalstacks + .get(rnd.nextInt(infernalstacks.size())) + .copy(); + EnchantmentHelper.addRandomEnchantment( + rnd, infernalstack, infernalstack.getItem().getItemEnchantability()); + stacks.add(infernalstack); + MTE.mEUt *= 8; + MTE.mMaxProgresstime *= mods * InfernalMobsCore.instance().getMobModHealthFactor(); + } + } + + return stacks.toArray(new ItemStack[0]); + } + } + + public static class MobDrop { + public enum DropType { + Normal, + Rare, + Additional, + Infernal + } + + public ItemStack stack; + public DropType type; + public int chance; + public Integer enchantable; + public HashMap<Integer, Integer> damages; + + public MobDrop( + ItemStack stack, DropType type, int chance, Integer enchantable, HashMap<Integer, Integer> damages) { + this.stack = stack; + this.type = type; + this.chance = chance; + this.enchantable = enchantable; + this.damages = damages; + } + } + + public static class fakeRand extends Random { + private static class nexter { + private final int type; + private final int bound; + private int next; + + public nexter(int type, int bound) { + this.next = 0; + this.bound = bound; + this.type = type; + } + + private int getType() { + return type; + } + + private boolean getBoolean() { + return next == 1; + } + + private int getInt() { + return next; + } + + private float getFloat() { + return next * 0.1f; + } + + private boolean next() { + next++; + return next >= bound; + } + } + + private final ArrayList<nexter> nexts = new ArrayList<>(); + private int walkCounter = 0; + private double chance; + private boolean exceptionOnEnchantTry = false; + private int maxWalkCount = -1; + private float forceFloatValue = -1.f; + + @Override + public int nextInt(int bound) { + if (exceptionOnEnchantTry && bound == Enchantment.enchantmentsBookList.length) return -1; + if (nexts.size() <= walkCounter) { // new call + if (maxWalkCount == walkCounter) { + return 0; + } + nexts.add(new nexter(0, bound)); + walkCounter++; + chance /= bound; + return 0; + } + chance /= bound; + return nexts.get(walkCounter++).getInt(); + } + + @Override + public float nextFloat() { + if (forceFloatValue != -1f) return forceFloatValue; + if (nexts.size() <= walkCounter) { // new call + if (maxWalkCount == walkCounter) { + return 0f; + } + nexts.add(new nexter(2, 10)); + walkCounter++; + chance /= 10; + return 0f; + } + chance /= 10; + return nexts.get(walkCounter++).getFloat(); + } + + @Override + public boolean nextBoolean() { + if (nexts.size() <= walkCounter) { // new call + if (maxWalkCount == walkCounter) { + return false; + } + nexts.add(new nexter(1, 2)); + walkCounter++; + chance /= 2; + return false; + } + chance /= 2; + return nexts.get(walkCounter++).getBoolean(); + } + + public void newRound() { + walkCounter = 0; + nexts.clear(); + chance = 1d; + maxWalkCount = -1; + exceptionOnEnchantTry = false; + forceFloatValue = -1f; + } + + public boolean nextRound() { + walkCounter = 0; + chance = 1d; + while (nexts.size() > 0 && nexts.get(nexts.size() - 1).next()) nexts.remove(nexts.size() - 1); + return nexts.size() > 0; + } + } + + private static class dropinstance { + public boolean isDamageRandomized = false; + public HashMap<Integer, Integer> damagesPossible = new HashMap<>(); + public boolean isEnchatmentRandomized = false; + public int enchantmentLevel = 0; + public final ItemStack stack; + public final GT_Utility.ItemId itemId; + private double dropchance = 0d; + private int dropcount = 1; + private final droplist owner; + + public dropinstance(ItemStack s, droplist owner) { + this.owner = owner; + stack = s; + itemId = GT_Utility.ItemId.createNoCopy(stack); + } + + public int getchance(int chancemodifier) { + dropchance = (double) Math.round(dropchance * 100000) / 100000d; + return (int) (dropchance * chancemodifier); + } + + @Override + public int hashCode() { + return itemId.hashCode(); + } + } + + public static class droplist { + private final ArrayList<dropinstance> drops = new ArrayList<>(); + private final HashMap<GT_Utility.ItemId, Integer> dropschecker = new HashMap<>(); + + public dropinstance add(dropinstance i, double chance) { + if (contains(i)) { + int ssize = i.stack.stackSize; + i = get(dropschecker.get(i.itemId)); + i.dropchance += chance * ssize; + i.dropcount += ssize; + return i; + } + drops.add(i); + i.dropchance += chance * i.stack.stackSize; + i.dropcount += i.stack.stackSize - 1; + i.stack.stackSize = 1; + dropschecker.put(i.itemId, drops.size() - 1); + return i; + } + + public dropinstance get(int index) { + return drops.get(index); + } + + public dropinstance get(dropinstance i) { + if (!contains(i)) return null; + return get(dropschecker.get(i.itemId)); + } + + public boolean contains(dropinstance i) { + return dropschecker.containsKey(i.itemId); + } + + public boolean contains(ItemStack stack) { + return dropschecker.containsKey(GT_Utility.ItemId.createNoCopy(stack)); + } + + public boolean isEmpty() { + return drops.isEmpty(); + } + + public int size() { + return drops.size(); + } + + public int indexOf(dropinstance i) { + if (!contains(i)) return -1; + return dropschecker.get(i.itemId); + } + } + + private static class dropCollector { + HashMap<GT_Utility.ItemId, Integer> damagableChecker = new HashMap<>(); + private boolean booksAlwaysRandomlyEnchanted = false; + + public void addDrop(droplist fdrops, ArrayList<EntityItem> listToParse, double chance) { + for (EntityItem entityItem : listToParse) { + ItemStack ostack = entityItem.getEntityItem(); + if (ostack == null) continue; + dropinstance drop; + boolean randomchomenchantdetected = + ostack.hasTagCompound() && ostack.stackTagCompound.hasKey(randomEnchantmentDetectedString); + int randomenchantmentlevel = 0; + if (randomchomenchantdetected) { + randomenchantmentlevel = ostack.stackTagCompound.getInteger(randomEnchantmentDetectedString); + ostack.stackTagCompound.removeTag("ench"); + } + if ((booksAlwaysRandomlyEnchanted || randomchomenchantdetected) + && Items.enchanted_book == ostack.getItem()) { + NBTTagCompound tagCompound = (NBTTagCompound) ostack.stackTagCompound.copy(); + tagCompound.removeTag("StoredEnchantments"); + ostack = new ItemStack(Items.book, ostack.stackSize, 0); + if (!tagCompound.hasNoTags()) ostack.stackTagCompound = tagCompound; + if (randomenchantmentlevel == 0) randomenchantmentlevel = 1; + randomchomenchantdetected = true; + } + boolean randomdamagedetected = false; + int newdamage = -1; + if (ostack.isItemStackDamageable()) { + int odamage = ostack.getItemDamage(); + ostack.setItemDamage(1); + GT_Utility.ItemId id = GT_Utility.ItemId.createNoCopy(ostack); + damagableChecker.putIfAbsent(id, odamage); + int check = damagableChecker.get(id); + if (check != odamage) { + randomdamagedetected = true; + newdamage = odamage; + ostack.setItemDamage(check); + } else ostack.setItemDamage(odamage); + } + drop = fdrops.add(new dropinstance(ostack.copy(), fdrops), chance); + if (!drop.isEnchatmentRandomized && randomchomenchantdetected) { + drop.isEnchatmentRandomized = true; + drop.enchantmentLevel = randomenchantmentlevel; + } + if (drop.isDamageRandomized && !randomdamagedetected) { + drop.damagesPossible.merge(drop.stack.getItemDamage(), 1, Integer::sum); + } + if (randomdamagedetected) { + if (!drop.isDamageRandomized) { + drop.isDamageRandomized = true; + drop.damagesPossible.merge(drop.stack.getItemDamage(), drop.dropcount - 1, Integer::sum); + } + if (newdamage == -1) newdamage = drop.stack.getItemDamage(); + drop.damagesPossible.merge(newdamage, 1, Integer::sum); + } + } + + listToParse.clear(); + } + + public void newRound() { + damagableChecker.clear(); + booksAlwaysRandomlyEnchanted = false; + } + } + + public static class GeneralMappedMob { + public final EntityLiving mob; + public final MobRecipe recipe; + public final ArrayList<MobDrop> drops; + + public GeneralMappedMob(EntityLiving mob, MobRecipe recipe, ArrayList<MobDrop> drops) { + this.mob = mob; + this.recipe = recipe; + this.drops = drops; + } + } + + public static final HashMap<String, GeneralMappedMob> GeneralMobList = new HashMap<>(); + + @SuppressWarnings("unchecked") + public static void generateMobRecipeMap() { + + if (alreadyGenerated) return; + alreadyGenerated = true; + if (!Config.mobHandlerEnabled) return; + + World f = new GT_DummyWorld() { + @Override + public boolean blockExists(int p_72899_1_, int p_72899_2_, int p_72899_3_) { + return false; + } + + @Override + public List getEntitiesWithinAABB(Class p_72872_1_, AxisAlignedBB p_72872_2_) { + return new ArrayList(); + } + }; + f.isRemote = true; // quick hack to get around achievements + + fakeRand frand = new fakeRand(); + f.rand = frand; + + isInGenerationProcess = true; + + LOG.info("Generating Recipe Map for Mob Handler and EEC"); + + long time = System.currentTimeMillis(); + + Method setSlimeSize; + Method dropFewItems; + Method dropRareDrop; + Method addRandomArmor; + Method enchantEquipment; + Field rand; + + try { + setSlimeSize = EntitySlime.class.getDeclaredMethod(setSlimeSizeName, int.class); + setSlimeSize.setAccessible(true); + dropFewItems = EntityLivingBase.class.getDeclaredMethod(dropFewItemsName, boolean.class, int.class); + dropFewItems.setAccessible(true); + dropRareDrop = EntityLivingBase.class.getDeclaredMethod(dropRareDropName, int.class); + dropRareDrop.setAccessible(true); + addRandomArmor = EntityLiving.class.getDeclaredMethod(addRandomArmorName); + addRandomArmor.setAccessible(true); + enchantEquipment = EntityLiving.class.getDeclaredMethod(enchantEquipmentName); + enchantEquipment.setAccessible(true); + rand = Entity.class.getDeclaredField(randName); + rand.setAccessible(true); + } catch (Exception ex) { + LOG.error("Failed to obtain methods"); + isInGenerationProcess = false; + return; + } + + dropCollector collector = new dropCollector(); + + // Stupid MC code, I need to cast myself + ((Map<String, Class<? extends Entity>>) EntityList.stringToClassMapping).forEach((k, v) -> { + if (v == null) return; + + LOG.info("Generating entry for mob: " + k); + + if (Modifier.isAbstract(v.getModifiers())) { + LOG.info("Entity " + k + " is abstract, skipping"); + return; + } + + EntityLiving e; + try { + e = (EntityLiving) v.getConstructor(new Class[] {World.class}).newInstance(new Object[] {f}); + } catch (ClassCastException ex) { + // not a EntityLiving + LOG.info("Entity " + k + " is not a LivingEntity, skipping"); + return; + } catch (NoSuchMethodException ex) { + // No constructor ? + LOG.info("Entity " + k + " doesn't have constructor, skipping"); + return; + } catch (Exception ex) { + ex.printStackTrace(); + return; + } + + if (StatCollector.translateToLocal("entity." + k + ".name").equals("entity." + k + ".name")) { + LOG.info("Entity " + k + " does't have localized name, skipping"); + return; + } + + e.captureDrops = true; + + // POWERFULL GENERATION + + if (e instanceof EntitySlime) + try { + setSlimeSize.invoke(e, 1); + } catch (Exception ex) { + ex.printStackTrace(); + return; + } + + try { + rand.set(e, frand); + } catch (Exception ex) { + ex.printStackTrace(); + return; + } + + droplist drops = new droplist(); + droplist raredrops = new droplist(); + droplist additionaldrops = new droplist(); + + LOG.info("Generating normal drops"); + + frand.newRound(); + collector.newRound(); + + if (v.getName().startsWith("com.emoniph.witchery")) { + try { + dropFewItems.invoke(e, true, 0); + } catch (Exception ex) { + ex.printStackTrace(); + return; + } + frand.newRound(); + frand.exceptionOnEnchantTry = true; + boolean enchantmentDetected = false; + try { + dropFewItems.invoke(e, true, 0); + } catch (Exception ex) { + enchantmentDetected = true; + } + int w = frand.walkCounter; + frand.newRound(); + if (enchantmentDetected) { + frand.maxWalkCount = w; + collector.booksAlwaysRandomlyEnchanted = true; + } + e.capturedDrops.clear(); + } + + do { + try { + dropFewItems.invoke(e, true, 0); + } catch (Exception ex) { + ex.printStackTrace(); + return; + } + collector.addDrop(drops, e.capturedDrops, frand.chance); + + if (frand.chance < 0.0000001d) { + LOG.info("Skipping " + k + " normal dropmap because it's too randomized"); + break; + } + + } while (frand.nextRound()); + + LOG.info("Generating rare drops"); + + frand.newRound(); + collector.newRound(); + + do { + try { + dropRareDrop.invoke(e, 0); + } catch (Exception ex) { + ex.printStackTrace(); + return; + } + collector.addDrop(raredrops, e.capturedDrops, frand.chance); + + if (frand.chance < 0.0000001d) { + LOG.info("Skipping " + k + " rare dropmap because it's too randomized"); + break; + } + } while (frand.nextRound()); + + LOG.info("Generating additional drops"); + + frand.newRound(); + collector.newRound(); + + try { + Class<?> cl = e.getClass(); + boolean detectedException = false; + do { + detectedException = false; + try { + cl.getDeclaredMethod(addRandomArmorName); + } catch (Exception ex) { + detectedException = true; + cl = cl.getSuperclass(); + } + } while (detectedException && !cl.equals(Entity.class)); + if (cl.equals(EntityLiving.class) || cl.equals(Entity.class)) throw new Exception(); + cl = e.getClass(); + do { + detectedException = false; + try { + cl.getDeclaredMethod(enchantEquipmentName); + } catch (Exception ex) { + detectedException = true; + cl = cl.getSuperclass(); + } + } while (detectedException && !cl.equals(EntityLiving.class)); + boolean usingVanillaEnchantingMethod = cl.equals(EntityLiving.class); + double chanceModifierLocal = 1f; + if (v.getName().startsWith("twilightforest.entity")) { + frand.forceFloatValue = 0f; + chanceModifierLocal = 0.25f; + } + do { + addRandomArmor.invoke(e); + if (!usingVanillaEnchantingMethod) enchantEquipment.invoke(e); + ItemStack[] lastActiveItems = e.getLastActiveItems(); + for (int j = 0, lastActiveItemsLength = lastActiveItems.length; j < lastActiveItemsLength; j++) { + ItemStack stack = lastActiveItems[j]; + if (stack != null) { + if (LoaderReference.Thaumcraft) + if (stack.getItem() instanceof ItemWandCasting) + continue; // crashes the game when rendering in GUI + + int randomenchant = -1; + if (stack.hasTagCompound() + && stack.stackTagCompound.hasKey(randomEnchantmentDetectedString)) { + randomenchant = stack.stackTagCompound.getInteger(randomEnchantmentDetectedString); + stack.stackTagCompound.removeTag("ench"); + } + dropinstance i = additionaldrops.add( + new dropinstance(stack.copy(), additionaldrops), + frand.chance + * chanceModifierLocal + * (usingVanillaEnchantingMethod ? (j == 0 ? 0.75d : 0.5d) : 1d)); + if (!i.isDamageRandomized && i.stack.isItemStackDamageable()) { + i.isDamageRandomized = true; + int maxdamage = i.stack.getMaxDamage(); + int max = Math.max(maxdamage - 25, 1); + for (int d = Math.min(max, 25); d <= max; d++) i.damagesPossible.put(d, 1); + } + if (!i.isEnchatmentRandomized && randomenchant != -1) { + i.isEnchatmentRandomized = true; + i.enchantmentLevel = randomenchant; + } + if (usingVanillaEnchantingMethod) { + if (!stack.hasTagCompound()) stack.stackTagCompound = new NBTTagCompound(); + stack.stackTagCompound.setInteger(randomEnchantmentDetectedString, 14); + dropinstance newdrop = additionaldrops.add( + new dropinstance(stack.copy(), additionaldrops), + frand.chance * chanceModifierLocal * (j == 0 ? 0.25d : 0.5d)); + newdrop.isEnchatmentRandomized = true; + newdrop.enchantmentLevel = 14; + newdrop.isDamageRandomized = i.isDamageRandomized; + newdrop.damagesPossible = (HashMap<Integer, Integer>) i.damagesPossible.clone(); + } + } + } + Arrays.fill(e.getLastActiveItems(), null); + + if (frand.chance < 0.0000001d) { + LOG.info("Skipping " + k + " additional dropmap because it's too randomized"); + break; + } + + } while (frand.nextRound()); + } catch (Exception ignored) { + } + + frand.newRound(); + collector.newRound(); + + if (drops.isEmpty() && raredrops.isEmpty() && additionaldrops.isEmpty()) { + GeneralMobList.put(k, new GeneralMappedMob(e, null, new ArrayList<>())); + LOG.info("Entity " + k + " doesn't drop any items, skipping EEC Recipe map"); + return; + } + + ArrayList<MobDrop> moboutputs = new ArrayList<>(drops.size() + raredrops.size() + additionaldrops.size()); + + for (dropinstance drop : drops.drops) { + ItemStack stack = drop.stack; + if (stack.hasTagCompound()) stack.stackTagCompound.removeTag(randomEnchantmentDetectedString); + int chance = drop.getchance(10000); + while (chance > 10000) { + stack.stackSize *= 2; + chance /= 2; + } + moboutputs.add(new MobDrop( + stack, + MobDrop.DropType.Normal, + chance, + drop.isEnchatmentRandomized ? drop.enchantmentLevel : null, + drop.isDamageRandomized ? drop.damagesPossible : null)); + } + for (dropinstance drop : raredrops.drops) { + ItemStack stack = drop.stack; + if (stack.hasTagCompound()) stack.stackTagCompound.removeTag(randomEnchantmentDetectedString); + int chance = drop.getchance(250); + while (chance > 10000) { + stack.stackSize *= 2; + chance /= 2; + } + moboutputs.add(new MobDrop( + stack, + MobDrop.DropType.Rare, + chance, + drop.isEnchatmentRandomized ? drop.enchantmentLevel : null, + drop.isDamageRandomized ? drop.damagesPossible : null)); + } + for (dropinstance drop : additionaldrops.drops) { + ItemStack stack = drop.stack; + if (stack.hasTagCompound()) stack.stackTagCompound.removeTag(randomEnchantmentDetectedString); + int chance = drop.getchance(850); + while (chance > 10000) { + stack.stackSize *= 2; + chance /= 2; + } + moboutputs.add(new MobDrop( + stack, + MobDrop.DropType.Additional, + chance, + drop.isEnchatmentRandomized ? drop.enchantmentLevel : null, + drop.isDamageRandomized ? drop.damagesPossible : null)); + } + + GeneralMobList.put(k, new GeneralMappedMob(e, new MobRecipe(e, moboutputs), moboutputs)); + + LOG.info("Mapped " + k); + }); + + time -= System.currentTimeMillis(); + time = -time; + + LOG.info("Recipe map generated ! It took " + time + "ms"); + + isInGenerationProcess = false; + } + + public static void processMobRecipeMap() { + LOG.info("Loading config"); + + if (isClientSided) Mob_Handler.clearRecipes(); + MobNameToRecipeMap.clear(); + LoadConfigPacket.instance.mobsToLoad.clear(); + GeneralMobList.forEach((k, v) -> { + if (Arrays.asList(Config.mobBlacklist).contains(k)) { + LOG.info("Entity " + k + " is blacklisted, skipping"); + return; + } + + MobRecipe recipe = v.recipe; + if (recipe != null) recipe = recipe.copy(); + ArrayList<MobDrop> drops = (ArrayList<MobDrop>) v.drops.clone(); + + // MT Scripts should already be loaded here + if (LoaderReference.MineTweaker) { + Optionals.parseMTAdditions(k, drops, recipe); + } + + if (drops.isEmpty()) { + LOG.info("Entity " + k + " doesn't drop any items, skipping EEC map"); + if (!Config.includeEmptyMobs) return; + LoadConfigPacket.instance.mobsToLoad.add(k); + LOG.info("Registered " + k); + return; + } + if (v.recipe != null) MobNameToRecipeMap.put(k, recipe); + LoadConfigPacket.instance.mobsToLoad.add(k); + LOG.info("Registered " + k); + }); + } + + @SideOnly(Side.CLIENT) + public static void processMobRecipeMap(HashSet<String> mobs) { + if (isClientSided) Mob_Handler.clearRecipes(); + MobNameToRecipeMap.clear(); + mobs.forEach(k -> { + GeneralMappedMob v = GeneralMobList.get(k); + MobRecipe recipe = v.recipe; + if (recipe != null) recipe = recipe.copy(); + ArrayList<MobDrop> drops = (ArrayList<MobDrop>) v.drops.clone(); + + // MT Scripts should already be loaded here + if (LoaderReference.MineTweaker) { + Optionals.parseMTAdditions(k, drops, recipe); + } + + Mob_Handler.addRecipe(v.mob, drops); + if (recipe != null) MobNameToRecipeMap.put(k, recipe); + LOG.info("Registered " + k); + }); + LOG.info("Sorting NEI map"); + Mob_Handler.sortCachedRecipes(); + } + + private static class Optionals { + private static void parseMTAdditions(String k, ArrayList<MobDrop> drops, MobRecipe recipe) { + IEntityDefinition ie = MineTweakerAPI.game.getEntity(k); + if (ie != null) { + for (Map.Entry<IItemStack, IntRange> entry : ie.getDropsToAdd().entrySet()) { + IntRange r = entry.getValue(); + // Get average chance + double chance; + if (r.getFrom() == 0 && r.getTo() == 0) chance = 1d; + else chance = (((double) r.getTo() - (double) r.getFrom()) / 2d) + (double) r.getFrom(); + ItemStack stack = ((ItemStack) entry.getKey().getInternal()).copy(); + MobDrop drop = new MobDrop(stack, MobDrop.DropType.Normal, (int) (chance * 10000), null, null); + drops.add(drop); + if (recipe != null) recipe.mOutputs.add(drop); + } + for (Map.Entry<IItemStack, IntRange> entry : + ie.getDropsToAddPlayerOnly().entrySet()) { + IntRange r = entry.getValue(); + // Get average chance + double chance; + if (r.getFrom() == 0 && r.getTo() == 0) chance = 1d; + else chance = (((double) r.getTo() - (double) r.getFrom()) / 2d) + (double) r.getFrom(); + ItemStack stack = ((ItemStack) entry.getKey().getInternal()).copy(); + MobDrop drop = new MobDrop(stack, MobDrop.DropType.Normal, (int) (chance * 10000), null, null); + drops.add(drop); + if (recipe != null) recipe.mOutputs.add(drop); + } + for (IItemStack istack : ie.getDropsToRemove()) { + List<MobDrop> toRemove = drops.stream() + .filter(d -> istack.matches(new MCItemStack(d.stack))) + .collect(Collectors.toList()); + drops.removeAll(toRemove); + if (recipe != null) recipe.mOutputs.removeAll(toRemove); + } + } + } + } +} |