From 6d436a2c6a5d9b51070b8399c4fdb196603a8e82 Mon Sep 17 00:00:00 2001 From: Jakub <53441451+kuba6000@users.noreply.github.com> Date: Sun, 14 Aug 2022 15:19:13 +0200 Subject: [PATCH] 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 --- build.gradle | 4 +- dependencies.gradle | 27 + gradle.properties | 6 +- repositories.gradle | 23 +- src/main/java/kubatech/ClientProxy.java | 8 + src/main/java/kubatech/CommonProxy.java | 20 +- src/main/java/kubatech/Config.java | 54 +- src/main/java/kubatech/FMLEventHandler.java | 16 + .../java/kubatech/api/LoaderReference.java | 12 + src/main/java/kubatech/api/Variables.java | 26 + .../java/kubatech/api/enums/ItemList.java | 167 +++ .../java/kubatech/api/utils/FastRandom.java | 27 + .../kubatech/api/utils/InfernalHelper.java | 226 ++++ .../java/kubatech/api/utils/ModUtils.java | 50 + .../kubatech/api/utils/ReflectionHelper.java | 62 ++ .../java/kubatech/commands/CommandConfig.java | 96 ++ .../kubatech/commands/CommandHandler.java | 115 +++ .../java/kubatech/commands/CommandHelp.java | 80 ++ ...ileEntity_ExtremeExterminationChamber.java | 394 +++++++ src/main/java/kubatech/kubatech.java | 26 +- .../kubatech/loaders/MobRecipeLoader.java | 973 ++++++++++++++++++ .../java/kubatech/loaders/RecipeLoader.java | 77 ++ src/main/java/kubatech/mixin/Mixin.java | 42 + src/main/java/kubatech/mixin/MixinPlugin.java | 110 ++ src/main/java/kubatech/mixin/TargetedMod.java | 35 + .../minecraft/EnchantmentHelperMixin.java | 40 + src/main/java/kubatech/nei/IMCForNEI.java | 76 ++ src/main/java/kubatech/nei/Mob_Handler.java | 592 +++++++++++ src/main/java/kubatech/nei/NEI_Config.java | 44 + .../kubatech/network/LoadConfigHandler.java | 36 + .../kubatech/network/LoadConfigPacket.java | 61 ++ .../resources/assets/kubatech/lang/en_US.lang | 25 + .../kubatech/textures/gui/MobHandler.png | Bin 0 -> 7548 bytes 33 files changed, 3537 insertions(+), 13 deletions(-) create mode 100644 src/main/java/kubatech/FMLEventHandler.java create mode 100644 src/main/java/kubatech/api/LoaderReference.java create mode 100644 src/main/java/kubatech/api/Variables.java create mode 100644 src/main/java/kubatech/api/enums/ItemList.java create mode 100644 src/main/java/kubatech/api/utils/FastRandom.java create mode 100644 src/main/java/kubatech/api/utils/InfernalHelper.java create mode 100644 src/main/java/kubatech/api/utils/ModUtils.java create mode 100644 src/main/java/kubatech/api/utils/ReflectionHelper.java create mode 100644 src/main/java/kubatech/commands/CommandConfig.java create mode 100644 src/main/java/kubatech/commands/CommandHandler.java create mode 100644 src/main/java/kubatech/commands/CommandHelp.java create mode 100644 src/main/java/kubatech/common/tileentity/gregtech/multiblock/GT_MetaTileEntity_ExtremeExterminationChamber.java create mode 100644 src/main/java/kubatech/loaders/MobRecipeLoader.java create mode 100644 src/main/java/kubatech/loaders/RecipeLoader.java create mode 100644 src/main/java/kubatech/mixin/Mixin.java create mode 100644 src/main/java/kubatech/mixin/MixinPlugin.java create mode 100644 src/main/java/kubatech/mixin/TargetedMod.java create mode 100644 src/main/java/kubatech/mixin/mixins/minecraft/EnchantmentHelperMixin.java create mode 100644 src/main/java/kubatech/nei/IMCForNEI.java create mode 100644 src/main/java/kubatech/nei/Mob_Handler.java create mode 100644 src/main/java/kubatech/nei/NEI_Config.java create mode 100644 src/main/java/kubatech/network/LoadConfigHandler.java create mode 100644 src/main/java/kubatech/network/LoadConfigPacket.java create mode 100644 src/main/resources/assets/kubatech/lang/en_US.lang create mode 100644 src/main/resources/assets/kubatech/textures/gui/MobHandler.png diff --git a/build.gradle b/build.gradle index ec6cfc96..4c2b5f59 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -//version: 1659365110 +//version: 1659977784 /* DO NOT CHANGE THIS FILE! Also, you may replace this file at any time if there is an update available. @@ -651,7 +651,7 @@ task updateBuildScript { } } -if (isNewBuildScriptVersionAvailable(projectDir.toString())) { +if (!project.getGradle().startParameter.isOffline() && isNewBuildScriptVersionAvailable(projectDir.toString())) { if (autoUpdateBuildScript.toBoolean()) { performBuildScriptUpdate(projectDir.toString()) } else { diff --git a/dependencies.gradle b/dependencies.gradle index b6456d02..39a4c44d 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,5 +1,32 @@ // Add your dependencies here dependencies { + compile("com.github.GTNewHorizons:GT5-Unofficial:5.09.40.78:dev") + compile("com.github.GTNewHorizons:EnderCore:0.2.6:dev") + compile("com.github.GTNewHorizons:EnderIO:2.3.1.29:dev") + compile("com.github.GTNewHorizons:Infernal-Mobs:1.7.5-GTNH:dev") + compileOnly("com.github.GTNewHorizons:BloodMagic:1.3.10:dev") + { + transitive = false + } + compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev") + { + transitive = false + } + compileOnly("com.github.GTNewHorizons:CraftTweaker:3.2.9:dev") + { + transitive = false + } + runtime("com.github.GTNewHorizons:Baubles:1.0.1.14:dev") + runtime("curse.maven:cofh-core-69162:2388751") + // For testing + //runtime("com.github.GTNewHorizons:OpenBlocks:1.6.9-GTNH:dev") + //runtime("com.github.GTNewHorizons:CraftTweaker:3.2.9:dev") + //compile("com.github.GTNewHorizons:SpecialMobs:3.3.12:dev") + //compile("com.github.GTNewHorizons:twilightforest:2.3.8.15:dev") + //compile("com.github.GTNewHorizons:EnderZoo:1.0.23:dev") + //runtime("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev") + //runtime("com.github.GTNewHorizons:BloodMagic:1.3.10:dev") + //compile("curse.maven:witchery-69673:2234410") } diff --git a/gradle.properties b/gradle.properties index 88a36b05..3fe7a4dc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -49,13 +49,13 @@ apiPackage = accessTransformersFile = # Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! -usesMixins = false +usesMixins = true # Adds some debug arguments like verbose output and export usesMixinDebug = false # Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise. -mixinPlugin = +mixinPlugin = mixin.MixinPlugin # Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail! -mixinsPackage = +mixinsPackage = mixin.mixins # Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! # This parameter is for legacy compatibility only # Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin diff --git a/repositories.gradle b/repositories.gradle index c8843905..92bcd9fb 100644 --- a/repositories.gradle +++ b/repositories.gradle @@ -1,5 +1,26 @@ // Add any additional repositories for your dependencies here repositories { - + maven { + name = "GTNH Maven" + url = "http://jenkins.usrv.eu:8081/nexus/content/groups/public/" + } + maven { + name = "ic2" + url = "http://maven.ic2.player.to/" + metadataSources { + mavenPom() + artifact() + } + } + maven { + url "https://cursemaven.com" + } + maven { + name = "jitpack.io" + url = "https://jitpack.io" + } + maven { + url 'https://repo.openmods.info/artifactory/openmods/' + } } diff --git a/src/main/java/kubatech/ClientProxy.java b/src/main/java/kubatech/ClientProxy.java index 8d676b30..f25f41ee 100644 --- a/src/main/java/kubatech/ClientProxy.java +++ b/src/main/java/kubatech/ClientProxy.java @@ -20,15 +20,23 @@ package kubatech; import cpw.mods.fml.common.event.*; +import kubatech.api.utils.ModUtils; +import kubatech.loaders.MobRecipeLoader; +import kubatech.nei.IMCForNEI; +import net.minecraftforge.common.MinecraftForge; +@SuppressWarnings("unused") public class ClientProxy extends CommonProxy { public void preInit(FMLPreInitializationEvent event) { + ModUtils.isClientSided = true; super.preInit(event); } public void init(FMLInitializationEvent event) { super.init(event); + IMCForNEI.IMCSender(); + MinecraftForge.EVENT_BUS.register(MobRecipeLoader.instance); } public void postInit(FMLPostInitializationEvent event) { diff --git a/src/main/java/kubatech/CommonProxy.java b/src/main/java/kubatech/CommonProxy.java index b058dc96..e844cd19 100644 --- a/src/main/java/kubatech/CommonProxy.java +++ b/src/main/java/kubatech/CommonProxy.java @@ -19,14 +19,22 @@ package kubatech; +import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.event.*; +import kubatech.commands.CommandConfig; +import kubatech.commands.CommandHandler; +import kubatech.commands.CommandHelp; +import kubatech.loaders.RecipeLoader; public class CommonProxy { public void preInit(FMLPreInitializationEvent event) { - Config.syncronizeConfiguration(event.getSuggestedConfigurationFile()); + kubatech.info("Initializing ! Version: " + Tags.VERSION); - kubatech.info("I am " + Tags.MODNAME + " at version " + Tags.VERSION); + Config.init(event.getSuggestedConfigurationFile()); + Config.synchronizeConfiguration(); + RecipeLoader.addRecipes(); + FMLCommonHandler.instance().bus().register(new FMLEventHandler()); } public void init(FMLInitializationEvent event) {} @@ -35,7 +43,13 @@ public void postInit(FMLPostInitializationEvent event) {} public void serverAboutToStart(FMLServerAboutToStartEvent event) {} - public void serverStarting(FMLServerStartingEvent event) {} + public void serverStarting(FMLServerStartingEvent event) { + RecipeLoader.addRecipesLate(); + CommandHandler cmd = new CommandHandler(); + cmd.addCommand(new CommandHelp()); + cmd.addCommand(new CommandConfig()); + event.registerServerCommand(cmd); + } public void serverStarted(FMLServerStartedEvent event) {} diff --git a/src/main/java/kubatech/Config.java b/src/main/java/kubatech/Config.java index b3af0fe9..439557d9 100644 --- a/src/main/java/kubatech/Config.java +++ b/src/main/java/kubatech/Config.java @@ -24,10 +24,62 @@ public class Config { - public static void syncronizeConfiguration(File configFile) { + private static class Categories { + public static final String mobHandler = "MobHandler"; + } + + public static boolean mobHandlerEnabled = true; + public static boolean includeEmptyMobs = true; + public static String[] mobBlacklist; + public static File configFile; + + public static void init(File configFile) { + Config.configFile = configFile; + } + + public static void synchronizeConfiguration() { Configuration configuration = new Configuration(configFile); configuration.load(); + mobHandlerEnabled = configuration + .get( + Categories.mobHandler, + "Enabled", + true, + "Enable \"Mob Drops\" NEI page and Extreme Extermination Chamber") + .getBoolean(); + includeEmptyMobs = configuration + .get(Categories.mobHandler, "IncludeEmptyMobs", true, "Include mobs that have no drops in NEI") + .getBoolean(); + mobBlacklist = configuration + .get( + Categories.mobHandler, + "MobBlacklist", + new String[] { + "Giant", + "Thaumcraft.TravelingTrunk", + "chisel.snowman", + "OpenBlocks.Luggage", + "OpenBlocks.MiniMe", + "SpecialMobs.SpecialCreeper", + "SpecialMobs.SpecialZombie", + "SpecialMobs.SpecialPigZombie", + "SpecialMobs.SpecialSlime", + "SpecialMobs.SpecialSkeleton", + "SpecialMobs.SpecialEnderman", + "SpecialMobs.SpecialCaveSpider", + "SpecialMobs.SpecialGhast", + "SpecialMobs.SpecialWitch", + "SpecialMobs.SpecialSpider", + "TwilightForest.HydraHead", + "TwilightForest.RovingCube", + "TwilightForest.Harbinger Cube", + "TwilightForest.Adherent", + "SpecialMobs.SpecialSilverfish", + }, + "These mobs will be skipped when generating recipe map") + .getStringList(); + if (configuration.hasChanged()) { configuration.save(); } diff --git a/src/main/java/kubatech/FMLEventHandler.java b/src/main/java/kubatech/FMLEventHandler.java new file mode 100644 index 00000000..e5acd58a --- /dev/null +++ b/src/main/java/kubatech/FMLEventHandler.java @@ -0,0 +1,16 @@ +package kubatech; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.PlayerEvent; +import kubatech.network.LoadConfigPacket; +import net.minecraft.entity.player.EntityPlayerMP; + +public class FMLEventHandler { + // Gets fired only server-sided + @SubscribeEvent + public void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) { + if (!(event.player instanceof EntityPlayerMP)) return; + kubatech.info("Sending config to " + event.player.getDisplayName()); + kubatech.NETWORK.sendTo(LoadConfigPacket.instance, (EntityPlayerMP) event.player); + } +} diff --git a/src/main/java/kubatech/api/LoaderReference.java b/src/main/java/kubatech/api/LoaderReference.java new file mode 100644 index 00000000..aef89309 --- /dev/null +++ b/src/main/java/kubatech/api/LoaderReference.java @@ -0,0 +1,12 @@ +package kubatech.api; + +import cpw.mods.fml.common.Loader; + +public class LoaderReference { + public static final boolean BloodMagic = Loader.isModLoaded("AWWayofTime"); + public static final boolean EnderIO = Loader.isModLoaded("EnderIO"); + public static final boolean ExtraUtilities = Loader.isModLoaded("ExtraUtilities"); + public static final boolean InfernalMobs = Loader.isModLoaded("InfernalMobs"); + public static final boolean Thaumcraft = Loader.isModLoaded("Thaumcraft"); + public static final boolean MineTweaker = Loader.isModLoaded("MineTweaker3"); +} diff --git a/src/main/java/kubatech/api/Variables.java b/src/main/java/kubatech/api/Variables.java new file mode 100644 index 00000000..c989b45f --- /dev/null +++ b/src/main/java/kubatech/api/Variables.java @@ -0,0 +1,26 @@ +/* + * 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 . + * + */ + +package kubatech.api; + +import net.minecraft.util.EnumChatFormatting; + +public class Variables { + public static final String Author = "Author: " + EnumChatFormatting.GOLD + "kuba6000"; +} diff --git a/src/main/java/kubatech/api/enums/ItemList.java b/src/main/java/kubatech/api/enums/ItemList.java new file mode 100644 index 00000000..b0cf3289 --- /dev/null +++ b/src/main/java/kubatech/api/enums/ItemList.java @@ -0,0 +1,167 @@ +package kubatech.api.enums; + +import static gregtech.api.enums.GT_Values.NI; +import static gregtech.api.enums.GT_Values.W; + +import gregtech.api.interfaces.IItemContainer; +import gregtech.api.util.GT_LanguageManager; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; +import java.util.Locale; +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +public enum ItemList implements IItemContainer { + ExtremeExterminationChamber; + + private ItemStack mStack; + private boolean mHasNotBeenSet = true; + + @Override + public IItemContainer set(Item aItem) { + mHasNotBeenSet = false; + if (aItem == null) return this; + ItemStack aStack = new ItemStack(aItem, 1, 0); + mStack = GT_Utility.copyAmount(1, aStack); + return this; + } + + @Override + public IItemContainer set(ItemStack aStack) { + mHasNotBeenSet = false; + mStack = GT_Utility.copyAmount(1, aStack); + return this; + } + + @Override + public Item getItem() { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return null; + return mStack.getItem(); + } + + @Override + public Block getBlock() { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + return GT_Utility.getBlockFromItem(getItem()); + } + + @Override + public final boolean hasBeenSet() { + return !mHasNotBeenSet; + } + + @Override + public boolean isStackEqual(Object aStack) { + return isStackEqual(aStack, false, false); + } + + @Override + public boolean isStackEqual(Object aStack, boolean aWildcard, boolean aIgnoreNBT) { + if (GT_Utility.isStackInvalid(aStack)) return false; + return GT_Utility.areUnificationsEqual((ItemStack) aStack, aWildcard ? getWildcard(1) : get(1), aIgnoreNBT); + } + + @Override + public ItemStack get(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return GT_Utility.copyAmount(aAmount, aReplacements); + return GT_Utility.copyAmount(aAmount, GT_OreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getWildcard(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return GT_Utility.copyAmount(aAmount, aReplacements); + return GT_Utility.copyAmountAndMetaData(aAmount, W, GT_OreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getUndamaged(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return GT_Utility.copyAmount(aAmount, aReplacements); + return GT_Utility.copyAmountAndMetaData(aAmount, 0, GT_OreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getAlmostBroken(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return GT_Utility.copyAmount(aAmount, aReplacements); + return GT_Utility.copyAmountAndMetaData(aAmount, mStack.getMaxDamage() - 1, GT_OreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getWithName(long aAmount, String aDisplayName, Object... aReplacements) { + ItemStack rStack = get(1, aReplacements); + if (GT_Utility.isStackInvalid(rStack)) return NI; + + // CamelCase alphanumeric words from aDisplayName + StringBuilder tCamelCasedDisplayNameBuilder = new StringBuilder(); + final String[] tDisplayNameWords = aDisplayName.split("\\W"); + for (String tWord : tDisplayNameWords) { + if (tWord.length() > 0) + tCamelCasedDisplayNameBuilder.append(tWord.substring(0, 1).toUpperCase(Locale.US)); + if (tWord.length() > 1) + tCamelCasedDisplayNameBuilder.append(tWord.substring(1).toLowerCase(Locale.US)); + } + if (tCamelCasedDisplayNameBuilder.length() == 0) { + // CamelCased DisplayName is empty, so use hash of aDisplayName + tCamelCasedDisplayNameBuilder.append(((Long) (long) aDisplayName.hashCode())); + } + + // Construct a translation key from UnlocalizedName and CamelCased DisplayName + final String tKey = rStack.getUnlocalizedName() + ".with." + tCamelCasedDisplayNameBuilder + ".name"; + + rStack.setStackDisplayName(GT_LanguageManager.addStringLocalization(tKey, aDisplayName)); + return GT_Utility.copyAmount(aAmount, rStack); + } + + @Override + public ItemStack getWithCharge(long aAmount, int aEnergy, Object... aReplacements) { + ItemStack rStack = get(1, aReplacements); + if (GT_Utility.isStackInvalid(rStack)) return null; + GT_ModHandler.chargeElectricItem(rStack, aEnergy, Integer.MAX_VALUE, true, false); + return GT_Utility.copyAmount(aAmount, rStack); + } + + @Override + public ItemStack getWithDamage(long aAmount, long aMetaValue, Object... aReplacements) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return GT_Utility.copyAmount(aAmount, aReplacements); + return GT_Utility.copyAmountAndMetaData(aAmount, aMetaValue, GT_OreDictUnificator.get(mStack)); + } + + @Override + public IItemContainer registerOre(Object... aOreNames) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + for (Object tOreName : aOreNames) GT_OreDictUnificator.registerOre(tOreName, get(1)); + return this; + } + + @Override + public IItemContainer registerWildcardAsOre(Object... aOreNames) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + for (Object tOreName : aOreNames) GT_OreDictUnificator.registerOre(tOreName, getWildcard(1)); + return this; + } + + /** + * Returns the internal stack. + * This method is unsafe. It's here only for quick operations. + * DON'T CHANGE THE RETURNED VALUE! + */ + public ItemStack getInternalStack_unsafe() { + return mStack; + } +} diff --git a/src/main/java/kubatech/api/utils/FastRandom.java b/src/main/java/kubatech/api/utils/FastRandom.java new file mode 100644 index 00000000..c0fb1ec9 --- /dev/null +++ b/src/main/java/kubatech/api/utils/FastRandom.java @@ -0,0 +1,27 @@ +package kubatech.api.utils; + +import java.util.Random; +import java.util.SplittableRandom; + +public class FastRandom extends Random { + + private SplittableRandom realRandom; + + public FastRandom() { + realRandom = new SplittableRandom(); + } + + public FastRandom(long seed) { + realRandom = new SplittableRandom(seed); + } + + @Override + public synchronized void setSeed(long seed) { + realRandom = new SplittableRandom(seed); + } + + @Override + protected int next(int bits) { + return (realRandom.nextInt() >>> (32 - bits)); + } +} diff --git a/src/main/java/kubatech/api/utils/InfernalHelper.java b/src/main/java/kubatech/api/utils/InfernalHelper.java new file mode 100644 index 00000000..d4e416e9 --- /dev/null +++ b/src/main/java/kubatech/api/utils/InfernalHelper.java @@ -0,0 +1,226 @@ +/* + * 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 . + * + */ + +package kubatech.api.utils; + +import atomicstryker.infernalmobs.common.InfernalMobsCore; +import atomicstryker.infernalmobs.common.mods.api.ModifierLoader; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; + +public class InfernalHelper { + private static Method isClassAllowed = null; + + public static boolean isClassAllowed(EntityLivingBase e) { + try { + if (isClassAllowed == null) { + isClassAllowed = InfernalMobsCore.class.getDeclaredMethod("isClassAllowed", EntityLivingBase.class); + isClassAllowed.setAccessible(true); + } + return (boolean) isClassAllowed.invoke(InfernalMobsCore.instance(), e); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return false; + } + + private static Method checkEntityClassForced = null; + + public static boolean checkEntityClassForced(EntityLivingBase e) { + try { + if (checkEntityClassForced == null) { + checkEntityClassForced = + InfernalMobsCore.class.getDeclaredMethod("checkEntityClassForced", EntityLivingBase.class); + checkEntityClassForced.setAccessible(true); + } + return (boolean) checkEntityClassForced.invoke(InfernalMobsCore.instance(), e); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return false; + } + + private static Field modifierLoaders = null; + + public static ArrayList> getModifierLoaders() { + try { + if (modifierLoaders == null) { + modifierLoaders = InfernalMobsCore.class.getDeclaredField("modifierLoaders"); + modifierLoaders.setAccessible(true); + } + return (ArrayList>) modifierLoaders.get(InfernalMobsCore.instance()); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return new ArrayList<>(); + } + + private static Field eliteRarity; + + public static int getEliteRarity() { + try { + if (eliteRarity == null) { + eliteRarity = InfernalMobsCore.class.getDeclaredField("eliteRarity"); + eliteRarity.setAccessible(true); + } + return eliteRarity.getInt(InfernalMobsCore.instance()); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return 15; + } + + private static Field ultraRarity; + + public static int getUltraRarity() { + try { + if (ultraRarity == null) { + ultraRarity = InfernalMobsCore.class.getDeclaredField("ultraRarity"); + ultraRarity.setAccessible(true); + } + return ultraRarity.getInt(InfernalMobsCore.instance()); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return 15; + } + + private static Field infernoRarity; + + public static int getInfernoRarity() { + try { + if (infernoRarity == null) { + infernoRarity = InfernalMobsCore.class.getDeclaredField("infernoRarity"); + infernoRarity.setAccessible(true); + } + return infernoRarity.getInt(InfernalMobsCore.instance()); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return 15; + } + + private static Field minEliteModifiers; + + public static int getMinEliteModifiers() { + try { + if (minEliteModifiers == null) { + minEliteModifiers = InfernalMobsCore.class.getDeclaredField("minEliteModifiers"); + minEliteModifiers.setAccessible(true); + } + return minEliteModifiers.getInt(InfernalMobsCore.instance()); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return 15; + } + + private static Field minUltraModifiers; + + public static int getMinUltraModifiers() { + try { + if (minUltraModifiers == null) { + minUltraModifiers = InfernalMobsCore.class.getDeclaredField("minUltraModifiers"); + minUltraModifiers.setAccessible(true); + } + return minUltraModifiers.getInt(InfernalMobsCore.instance()); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return 15; + } + + private static Field minInfernoModifiers; + + public static int getMinInfernoModifiers() { + try { + if (minInfernoModifiers == null) { + minInfernoModifiers = InfernalMobsCore.class.getDeclaredField("minInfernoModifiers"); + minInfernoModifiers.setAccessible(true); + } + return minInfernoModifiers.getInt(InfernalMobsCore.instance()); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return 15; + } + + private static Field dimensionBlackList; + + public static ArrayList getDimensionBlackList() { + try { + if (dimensionBlackList == null) { + dimensionBlackList = InfernalMobsCore.class.getDeclaredField("dimensionBlackList"); + dimensionBlackList.setAccessible(true); + } + return (ArrayList) dimensionBlackList.get(InfernalMobsCore.instance()); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return new ArrayList<>(); + } + + private static Field dropIdListElite; + + public static ArrayList getDropIdListElite() { + try { + if (dropIdListElite == null) { + dropIdListElite = InfernalMobsCore.class.getDeclaredField("dropIdListElite"); + dropIdListElite.setAccessible(true); + } + return (ArrayList) dropIdListElite.get(InfernalMobsCore.instance()); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return new ArrayList<>(); + } + + private static Field dropIdListUltra; + + public static ArrayList getDropIdListUltra() { + try { + if (dropIdListUltra == null) { + dropIdListUltra = InfernalMobsCore.class.getDeclaredField("dropIdListUltra"); + dropIdListUltra.setAccessible(true); + } + return (ArrayList) dropIdListUltra.get(InfernalMobsCore.instance()); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return new ArrayList<>(); + } + + private static Field dropIdListInfernal; + + public static ArrayList getDropIdListInfernal() { + try { + if (dropIdListInfernal == null) { + dropIdListInfernal = InfernalMobsCore.class.getDeclaredField("dropIdListInfernal"); + dropIdListInfernal.setAccessible(true); + } + return (ArrayList) dropIdListInfernal.get(InfernalMobsCore.instance()); + } catch (Throwable exception) { + exception.printStackTrace(); + } + return new ArrayList<>(); + } +} diff --git a/src/main/java/kubatech/api/utils/ModUtils.java b/src/main/java/kubatech/api/utils/ModUtils.java new file mode 100644 index 00000000..08022949 --- /dev/null +++ b/src/main/java/kubatech/api/utils/ModUtils.java @@ -0,0 +1,50 @@ +/* + * 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 . + * + */ + +package kubatech.api.utils; + +import cpw.mods.fml.common.Loader; +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.Map; +import net.minecraft.launchwrapper.Launch; + +public class ModUtils { + public static final boolean isDeobfuscatedEnvironment = + (boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment"); + public static boolean isClientSided = false; + private static final HashMap classNamesToModIDs = new HashMap<>(); + private static final Map.Entry emptyEntry = new AbstractMap.SimpleEntry<>("", ""); + + public static String getModNameFromClassName(String classname) { + if (classNamesToModIDs.size() == 0) { + classNamesToModIDs.put("net.minecraft", "Minecraft"); + Loader.instance().getActiveModList().forEach(m -> { + Object Mod = m.getMod(); + if (Mod != null) + classNamesToModIDs.put(Mod.getClass().getPackage().getName(), m.getName()); + }); + } + return classNamesToModIDs.entrySet().stream() + .filter(e -> classname.startsWith(e.getKey())) + .findAny() + .orElse(emptyEntry) + .getValue(); + } +} diff --git a/src/main/java/kubatech/api/utils/ReflectionHelper.java b/src/main/java/kubatech/api/utils/ReflectionHelper.java new file mode 100644 index 00000000..0e5d40e2 --- /dev/null +++ b/src/main/java/kubatech/api/utils/ReflectionHelper.java @@ -0,0 +1,62 @@ +/* + * 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 . + * + */ + +package kubatech.api.utils; + +import java.lang.reflect.Field; +import java.util.HashMap; + +public class ReflectionHelper { + private static final HashMap> fields = new HashMap<>(); + + public static T getField(Object obj, String fieldName, boolean useBasicTypes, T defaultvalue) { + Class cl = obj.getClass(); + String clName = cl.getName(); + HashMap classmap = fields.computeIfAbsent(clName, s -> new HashMap<>()); + try { + if (classmap.containsKey(fieldName)) { + return (T) classmap.get(fieldName).get(obj); + } + boolean exceptionDetected = false; + Field f = null; + do { + try { + f = cl.getDeclaredField(fieldName); + f.setAccessible(true); + } catch (Exception ex) { + exceptionDetected = true; + cl = cl.getSuperclass(); + } + } while (exceptionDetected && !cl.equals(Object.class)); + if (f == null) return defaultvalue; + classmap.put(fieldName, f); + return (T) f.get(obj); + } catch (Exception ex) { + return defaultvalue; + } + } + + public static T getField(Object obj, String fieldName, boolean useBasicTypes) { + return getField(obj, fieldName, useBasicTypes, null); + } + + public static T getField(Object obj, String fieldName) { + return getField(obj, fieldName, true, null); + } +} diff --git a/src/main/java/kubatech/commands/CommandConfig.java b/src/main/java/kubatech/commands/CommandConfig.java new file mode 100644 index 00000000..f3bcbb77 --- /dev/null +++ b/src/main/java/kubatech/commands/CommandConfig.java @@ -0,0 +1,96 @@ +/* + * 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 . + * + */ + +package kubatech.commands; + +import static kubatech.commands.CommandConfig.Translations.*; + +import kubatech.Config; +import kubatech.kubatech; +import kubatech.loaders.MobRecipeLoader; +import kubatech.network.LoadConfigPacket; +import net.minecraft.command.CommandBase; +import net.minecraft.command.ICommandSender; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.StatCollector; + +public class CommandConfig extends CommandBase { + enum Translations { + INVALID_OPTION, + SUCCESS, + USAGE, + ; + final String key; + + Translations() { + key = "command.config." + 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(); + } + } + + @Override + public String getCommandName() { + return "config"; + } + + @Override + public String getCommandUsage(ICommandSender p_71518_1_) { + return "config " + USAGE.get(); + } + + @Override + public int getRequiredPermissionLevel() { + return 4; + } + + @SuppressWarnings("unchecked") + @Override + public void processCommand(ICommandSender p_71515_1_, String[] p_71515_2_) { + if (p_71515_2_.length == 0 || !p_71515_2_[0].equals("reload")) { + p_71515_1_.addChatMessage(new ChatComponentText(INVALID_OPTION.get())); + return; + } + Config.synchronizeConfiguration(); + MobRecipeLoader.processMobRecipeMap(); + MinecraftServer.getServer().getConfigurationManager().playerEntityList.forEach(p -> { + if (!(p instanceof EntityPlayerMP)) return; + kubatech.info("Sending config to " + ((EntityPlayerMP) p).getDisplayName()); + kubatech.NETWORK.sendTo(LoadConfigPacket.instance, (EntityPlayerMP) p); + }); + p_71515_1_.addChatMessage(new ChatComponentText(SUCCESS.get())); + } +} diff --git a/src/main/java/kubatech/commands/CommandHandler.java b/src/main/java/kubatech/commands/CommandHandler.java new file mode 100644 index 00000000..6f328394 --- /dev/null +++ b/src/main/java/kubatech/commands/CommandHandler.java @@ -0,0 +1,115 @@ +/* + * 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 . + * + */ + +package kubatech.commands; + +import static kubatech.commands.CommandHandler.Translations.*; + +import java.util.*; +import net.minecraft.command.CommandBase; +import net.minecraft.command.ICommand; +import net.minecraft.command.ICommandSender; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; + +public class CommandHandler extends CommandBase { + enum Translations { + INVALID, + CANT_FIND, + GENERIC_HELP, + USAGE, + ; + final String key; + + Translations() { + key = "commandhandler." + 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 ArrayList aliases = new ArrayList<>(Collections.singleton("kt")); + public static final HashMap commands = new HashMap<>(); + + @Override + public String getCommandName() { + return "kubatech"; + } + + @Override + public String getCommandUsage(ICommandSender p_71518_1_) { + return "kubatech " + USAGE.get(); + } + + @Override + public List getCommandAliases() { + return aliases; + } + + @Override + public void processCommand(ICommandSender p_71515_1_, String[] p_71515_2_) { + if (p_71515_1_.getEntityWorld().isRemote) return; + if (p_71515_2_.length == 0) { + p_71515_1_.addChatMessage(new ChatComponentText(INVALID.get(getCommandUsage(p_71515_1_)))); + p_71515_1_.addChatMessage(new ChatComponentText(GENERIC_HELP.get())); + return; + } + if (!commands.containsKey(p_71515_2_[0])) { + p_71515_1_.addChatMessage(new ChatComponentText(CANT_FIND.get(p_71515_2_[0]))); + p_71515_1_.addChatMessage(new ChatComponentText(GENERIC_HELP.get())); + return; + } + ICommand cmd = commands.get(p_71515_2_[0]); + if (!cmd.canCommandSenderUseCommand(p_71515_1_)) { + ChatComponentTranslation chatcomponenttranslation2 = + new ChatComponentTranslation("commands.generic.permission"); + chatcomponenttranslation2.getChatStyle().setColor(EnumChatFormatting.RED); + p_71515_1_.addChatMessage(chatcomponenttranslation2); + } else + cmd.processCommand( + p_71515_1_, + p_71515_2_.length > 1 ? Arrays.copyOfRange(p_71515_2_, 1, p_71515_2_.length) : new String[0]); + } + + @Override + public boolean canCommandSenderUseCommand(ICommandSender p_71519_1_) { + return true; + } + + public void addCommand(ICommand command) { + commands.put(command.getCommandName(), command); + } +} diff --git a/src/main/java/kubatech/commands/CommandHelp.java b/src/main/java/kubatech/commands/CommandHelp.java new file mode 100644 index 00000000..0165e67c --- /dev/null +++ b/src/main/java/kubatech/commands/CommandHelp.java @@ -0,0 +1,80 @@ +/* + * 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 . + * + */ + +package kubatech.commands; + +import static kubatech.commands.CommandHelp.Translations.*; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.ICommandSender; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.StatCollector; + +public class CommandHelp extends CommandBase { + enum Translations { + POSSIBLE_COMMANDS, + USAGE, + ; + final String key; + + Translations() { + key = "command.help." + 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(); + } + } + + @Override + public String getCommandName() { + return "help"; + } + + @Override + public String getCommandUsage(ICommandSender p_71518_1_) { + return "help " + USAGE.get(); + } + + @Override + public boolean canCommandSenderUseCommand(ICommandSender p_71519_1_) { + return true; + } + + @Override + public void processCommand(ICommandSender p_71515_1_, String[] p_71515_2_) { + p_71515_1_.addChatMessage(new ChatComponentText(POSSIBLE_COMMANDS.get())); + CommandHandler.commands.values().forEach(c -> { + p_71515_1_.addChatMessage(new ChatComponentText("/kubatech " + c.getCommandUsage(p_71515_1_))); + }); + } +} diff --git a/src/main/java/kubatech/common/tileentity/gregtech/multiblock/GT_MetaTileEntity_ExtremeExterminationChamber.java b/src/main/java/kubatech/common/tileentity/gregtech/multiblock/GT_MetaTileEntity_ExtremeExterminationChamber.java new file mode 100644 index 00000000..f02599f3 --- /dev/null +++ b/src/main/java/kubatech/common/tileentity/gregtech/multiblock/GT_MetaTileEntity_ExtremeExterminationChamber.java @@ -0,0 +1,394 @@ +/* + * 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 . + * + */ + +package kubatech.common.tileentity.gregtech.multiblock; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.*; +import static gregtech.api.enums.Textures.BlockIcons.*; +import static gregtech.api.util.GT_StructureUtility.ofHatchAdder; +import static kubatech.api.Variables.Author; + +import WayofTime.alchemicalWizardry.api.alchemy.energy.ReagentRegistry; +import WayofTime.alchemicalWizardry.api.event.RitualRunEvent; +import WayofTime.alchemicalWizardry.api.rituals.Rituals; +import WayofTime.alchemicalWizardry.api.soulNetwork.SoulNetworkHandler; +import WayofTime.alchemicalWizardry.api.tile.IBloodAltar; +import WayofTime.alchemicalWizardry.common.rituals.RitualEffectWellOfSuffering; +import WayofTime.alchemicalWizardry.common.tileEntity.TEMasterStone; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import cpw.mods.fml.common.eventhandler.EventPriority; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import crazypants.enderio.EnderIO; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; +import java.util.HashMap; +import java.util.Random; +import kubatech.Tags; +import kubatech.api.LoaderReference; +import kubatech.api.utils.FastRandom; +import kubatech.api.utils.ReflectionHelper; +import kubatech.loaders.MobRecipeLoader; +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.world.EnumDifficulty; +import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +public class GT_MetaTileEntity_ExtremeExterminationChamber + extends GT_MetaTileEntity_EnhancedMultiBlockBase { + + public static final HashMap MobNameToRecipeMap = new HashMap<>(); + public final Random rand = new FastRandom(); + + public GT_MetaTileEntity_ExtremeExterminationChamber(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_ExtremeExterminationChamber(String aName) { + super(aName); + if (LoaderReference.BloodMagic) MinecraftForge.EVENT_BUS.register(this); + } + + @Override + public void onRemoval() { + if (LoaderReference.BloodMagic) MinecraftForge.EVENT_BUS.unregister(this); + } + + private static final String WellOfSufferingRitualName = "AW013Suffering"; + + private static final Item poweredSpawnerItem = Item.getItemFromBlock(EnderIO.blockPoweredSpawner); + private static final int CASING_INDEX = 16; + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final IStructureDefinition STRUCTURE_DEFINITION = + StructureDefinition.builder() + .addShape(STRUCTURE_PIECE_MAIN, transpose(new String[][] { + {"ccccc", "ccccc", "ccccc", "ccccc", "ccccc"}, + {"ccccc", "c---c", "c---c", "c---c", "ccccc"}, + {"ccccc", "c---c", "c---c", "c---c", "ccccc"}, + {"ccccc", "c---c", "c---c", "c---c", "ccccc"}, + {"ccccc", "c---c", "c---c", "c---c", "ccccc"}, + {"ccccc", "csssc", "csssc", "csssc", "ccccc"}, + {"CC~CC", "CCCCC", "CCCCC", "CCCCC", "CCCCC"}, + })) + .addElement('c', onElementPass(t -> t.mCasing++, ofBlock(GregTech_API.sBlockCasings2, 0))) + .addElement( + 'C', + ofChain( + onElementPass(t -> t.mCasing++, ofBlock(GregTech_API.sBlockCasings2, 0)), + ofHatchAdder( + GT_MetaTileEntity_ExtremeExterminationChamber::addOutputToMachineList, + CASING_INDEX, + 1), + ofHatchAdder( + GT_MetaTileEntity_ExtremeExterminationChamber::addEnergyInputToMachineList, + CASING_INDEX, + 1), + ofHatchAdder( + GT_MetaTileEntity_ExtremeExterminationChamber::addMaintenanceToMachineList, + CASING_INDEX, + 1))) + .addElement( + 's', + LoaderReference.ExtraUtilities + ? ofBlock(Block.getBlockFromName("ExtraUtilities:spike_base_diamond"), 0) + : isAir()) + .build(); + + private TileEntity masterStoneRitual = null; + private TileEntity tileAltar = null; + private boolean isInRitualMode = false; + private int mCasing = 0; + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setBoolean("isInRitualMode", isInRitualMode); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + isInRitualMode = aNBT.getBoolean("isInRitualMode"); + } + + @Override + public IStructureDefinition getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Powered Spawner") + .addInfo("Controller block for Extreme Extermination Chamber") + .addInfo("Spawns and Exterminates monsters for you") + .addInfo("Base energy usage: 2,000 EU/t") + .addInfo("Recipe time is based on mob health") + .addInfo("Also produces 120 Liquid XP per operation") + .addInfo("If the mob spawns infernal") + .addInfo("it will drain 8 times more power") + .addInfo("You can enable ritual mode with a screwdriver") + .addInfo("When in ritual mode and Well Of Suffering ritual is built directly on the machine in center") + .addInfo("The mobs will start to buffer and die very slowly by a ritual") + .addInfo(Author) + .addSeparator() + .beginStructureBlock(5, 7, 5, true) + .addController("Front Bottom Center") + .addCasingInfo("Solid Steel Machine Casing", 10) + .addOutputBus("Any casing", 1) + .addOutputHatch("Any casing", 1) + .addEnergyHatch("Any casing", 1) + .addMaintenanceHatch("Any casing", 1) + .toolTipFinisher(Tags.MODNAME); + return tt; + } + + @Override + public void construct(ItemStack itemStack, boolean b) { + buildPiece(STRUCTURE_PIECE_MAIN, itemStack, b, 2, 6, 0); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_ExtremeExterminationChamber(this.mName); + } + + @Override + public ITexture[] getTexture( + IGregTechTileEntity aBaseMetaTileEntity, + byte aSide, + byte aFacing, + byte aColorIndex, + boolean aActive, + boolean aRedstone) { + if (aSide == aFacing) { + if (aActive) + return new ITexture[] { + Textures.BlockIcons.getCasingTextureForId(CASING_INDEX), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE_GLOW) + .extFacing() + .glow() + .build() + }; + return new ITexture[] { + Textures.BlockIcons.getCasingTextureForId(CASING_INDEX), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_GLOW) + .extFacing() + .glow() + .build() + }; + } + return new ITexture[] {Textures.BlockIcons.getCasingTextureForId(CASING_INDEX)}; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + } + + @Override + public void onScrewdriverRightClick(byte aSide, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (!LoaderReference.BloodMagic) return; + if (this.mMaxProgresstime > 0) { + GT_Utility.sendChatToPlayer(aPlayer, "Can't change mode when running !"); + return; + } + isInRitualMode = !isInRitualMode; + if (!isInRitualMode) { + GT_Utility.sendChatToPlayer(aPlayer, "Ritual mode disabled"); + } else { + GT_Utility.sendChatToPlayer(aPlayer, "Ritual mode enabled"); + if (connectToRitual()) GT_Utility.sendChatToPlayer(aPlayer, "Successfully connected to the ritual"); + else GT_Utility.sendChatToPlayer(aPlayer, "Can't connect to the ritual"); + } + } + + @SuppressWarnings("unused") + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onRitualPerform(RitualRunEvent event) { + if (!isInRitualMode) return; + if (masterStoneRitual == null) return; + if (this.mMaxProgresstime == 0) return; + if (event.mrs.equals(masterStoneRitual) && event.ritualKey.equals(WellOfSufferingRitualName)) { + Rituals ritual = Rituals.ritualMap.get(WellOfSufferingRitualName); + if (ritual != null && ritual.effect instanceof RitualEffectWellOfSuffering) { + RitualEffectWellOfSuffering effect = (RitualEffectWellOfSuffering) ritual.effect; + event.setCanceled(true); // we will handle that + String owner = event.mrs.getOwner(); + int currentEssence = SoulNetworkHandler.getCurrentEssence(owner); + World world = event.mrs.getWorld(); + int x = event.mrs.getXCoord(); + int y = event.mrs.getYCoord(); + int z = event.mrs.getZCoord(); + + if (world.getWorldTime() % RitualEffectWellOfSuffering.timeDelay != 0) return; + + if (tileAltar == null || tileAltar.isInvalid()) { + tileAltar = null; + for (int i = -5; i <= 5; i++) + for (int j = -5; j <= 5; j++) + for (int k = -10; k <= 10; k++) + if (world.getTileEntity(x + i, y + k, z + j) instanceof IBloodAltar) + tileAltar = world.getTileEntity(x + i, y + k, z + j); + } + if (tileAltar == null) return; + + if (currentEssence < effect.getCostPerRefresh() * 100) SoulNetworkHandler.causeNauseaToPlayer(owner); + + ((IBloodAltar) tileAltar) + .sacrificialDaggerCall( + 100 + * RitualEffectWellOfSuffering.amount + * (effect.canDrainReagent( + event.mrs, + ReagentRegistry.offensaReagent, + ReflectionHelper.getField(effect, "offensaDrain", true, 3), + true) + ? 2 + : 1) + * (effect.canDrainReagent( + event.mrs, + ReagentRegistry.tenebraeReagent, + ReflectionHelper.getField(effect, "tennebraeDrain", true, 5), + true) + ? 2 + : 1), + true); + + SoulNetworkHandler.syphonFromNetwork(owner, effect.getCostPerRefresh() * 100); + } + } + } + + @Override + public boolean checkRecipe(ItemStack aStack) { + if (aStack == null) return false; + + if (aStack.getItem() != poweredSpawnerItem) return false; + + if (aStack.getTagCompound() == null) return false; + String mobType = aStack.getTagCompound().getString("mobType"); + if (mobType.isEmpty()) return false; + + MobRecipeLoader.MobRecipe recipe = MobNameToRecipeMap.get(mobType); + + if (recipe == null) return false; + if (!recipe.isPeacefulAllowed + && this.getBaseMetaTileEntity().getWorld().difficultySetting == EnumDifficulty.PEACEFUL) return false; + + this.mOutputItems = recipe.generateOutputs(rand, this); + + if (isInRitualMode && isRitualValid()) { + this.mMaxProgresstime = 400; + this.mEUt /= 4; + this.mOutputFluids = new FluidStack[] {FluidRegistry.getFluidStack("xpjuice", 5000)}; + } else { + calculateOverclockedNessMulti(this.mEUt, this.mMaxProgresstime, 2, getMaxInputVoltage()); + this.mOutputFluids = new FluidStack[] {FluidRegistry.getFluidStack("xpjuice", 120)}; + } + if (this.mEUt > 0) this.mEUt = -this.mEUt; + this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); + this.mEfficiencyIncrease = 10000; + + return true; + } + + private boolean isRitualValid() { + if (!isInRitualMode) return false; + if (masterStoneRitual == null) return false; + if (masterStoneRitual.isInvalid() + || !(((TEMasterStone) masterStoneRitual).getCurrentRitual().equals(WellOfSufferingRitualName))) { + masterStoneRitual = null; + return false; + } + return true; + } + + private boolean connectToRitual() { + if (!LoaderReference.BloodMagic) return false; + ChunkCoordinates coords = this.getBaseMetaTileEntity().getCoords(); + int[] abc = new int[] {0, -8, 2}; + int[] xyz = new int[] {0, 0, 0}; + this.getExtendedFacing().getWorldOffset(abc, xyz); + xyz[0] += coords.posX; + xyz[1] += coords.posY; + xyz[2] += coords.posZ; + TileEntity te = this.getBaseMetaTileEntity().getTileEntity(xyz[0], xyz[1], xyz[2]); + if (te instanceof TEMasterStone) { + if (((TEMasterStone) te).getCurrentRitual().equals(WellOfSufferingRitualName)) { + masterStoneRitual = te; + return true; + } + } + return false; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + if (!checkPiece(STRUCTURE_PIECE_MAIN, 2, 6, 0)) return false; + if (mCasing < 10 || mMaintenanceHatches.size() != 1 || mEnergyHatches.size() == 0) return false; + if (isInRitualMode) connectToRitual(); + return true; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } +} diff --git a/src/main/java/kubatech/kubatech.java b/src/main/java/kubatech/kubatech.java index 187fa255..893928ea 100644 --- a/src/main/java/kubatech/kubatech.java +++ b/src/main/java/kubatech/kubatech.java @@ -1,5 +1,5 @@ /* - * kubatech - Gregtech Addon + * KubaTech - Gregtech Addon * Copyright (C) 2022 kuba6000 * * This program is free software: you can redistribute it and/or modify @@ -22,19 +22,39 @@ import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.SidedProxy; import cpw.mods.fml.common.event.*; +import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper; +import cpw.mods.fml.relauncher.Side; +import kubatech.network.LoadConfigHandler; +import kubatech.network.LoadConfigPacket; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -@Mod(modid = Tags.MODID, version = Tags.VERSION, name = Tags.MODNAME, acceptedMinecraftVersions = "[1.7.10]") +@SuppressWarnings("unused") +@Mod( + modid = Tags.MODID, + version = Tags.VERSION, + name = Tags.MODNAME, + acceptedMinecraftVersions = "[1.7.10]", + dependencies = "required-after:gregtech; " + "required-after:spongemixins@[1.4.0,); " + "after:EnderIO; " + + "after:AWWayofTime; " + "after:ExtraUtilities; " + "after: InfernalMobs; " + "after: Thaumcraft; " + + "after: MineTweaker3; ") public class kubatech { - private static Logger LOG = LogManager.getLogger(Tags.MODID); + public static kubatech instance = null; + public static final SimpleNetworkWrapper NETWORK = new SimpleNetworkWrapper(Tags.MODID); + + static { + NETWORK.registerMessage(new LoadConfigHandler(), LoadConfigPacket.class, 0, Side.CLIENT); + } + + private static final Logger LOG = LogManager.getLogger(Tags.MODID); @SidedProxy(clientSide = Tags.MODID + ".ClientProxy", serverSide = Tags.MODID + ".CommonProxy") public static CommonProxy proxy; @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { + instance = this; proxy.preInit(event); } diff --git a/src/main/java/kubatech/loaders/MobRecipeLoader.java b/src/main/java/kubatech/loaders/MobRecipeLoader.java new file mode 100644 index 00000000..033beb49 --- /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 . + * + */ + +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 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) mOutputs.clone(), + mDuration, + mMaxDamageChance, + infernalityAllowed, + alwaysinfernal, + isPeacefulAllowed); + } + + private MobRecipe( + ArrayList 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 outputs) { + if (infernaldrops == null && LoaderReference.InfernalMobs) { + infernaldrops = new droplist(); + LOG.info("Generating Infernal drops"); + ArrayList> modifierLoaders = (ArrayList>) + 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 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 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 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 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 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 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 damages; + + public MobDrop( + ItemStack stack, DropType type, int chance, Integer enchantable, HashMap 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 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 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 drops = new ArrayList<>(); + private final HashMap 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 damagableChecker = new HashMap<>(); + private boolean booksAlwaysRandomlyEnchanted = false; + + public void addDrop(droplist fdrops, ArrayList 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 drops; + + public GeneralMappedMob(EntityLiving mob, MobRecipe recipe, ArrayList drops) { + this.mob = mob; + this.recipe = recipe; + this.drops = drops; + } + } + + public static final HashMap 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>) 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) 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 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 drops = (ArrayList) 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 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 drops = (ArrayList) 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 drops, MobRecipe recipe) { + IEntityDefinition ie = MineTweakerAPI.game.getEntity(k); + if (ie != null) { + for (Map.Entry 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 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 toRemove = drops.stream() + .filter(d -> istack.matches(new MCItemStack(d.stack))) + .collect(Collectors.toList()); + drops.removeAll(toRemove); + if (recipe != null) recipe.mOutputs.removeAll(toRemove); + } + } + } + } +} diff --git a/src/main/java/kubatech/loaders/RecipeLoader.java b/src/main/java/kubatech/loaders/RecipeLoader.java new file mode 100644 index 00000000..99908a85 --- /dev/null +++ b/src/main/java/kubatech/loaders/RecipeLoader.java @@ -0,0 +1,77 @@ +/* + * 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 . + * + */ + +package kubatech.loaders; + +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.util.GT_ModHandler; +import kubatech.Tags; +import kubatech.api.LoaderReference; +import kubatech.api.enums.ItemList; +import kubatech.common.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeExterminationChamber; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class RecipeLoader { + + private static final Logger LOG = LogManager.getLogger(Tags.MODID + "[Recipe Loader]"); + protected static final long bitsd = GT_ModHandler.RecipeBits.NOT_REMOVABLE + | GT_ModHandler.RecipeBits.REVERSIBLE + | GT_ModHandler.RecipeBits.BUFFERED + | GT_ModHandler.RecipeBits.DISMANTLEABLE; + + private static int MTEID = 14201; + private static final int MTEIDMax = 14300; + + public static void addRecipes() { + if (LoaderReference.EnderIO) { + ItemList.ExtremeExterminationChamber.set(new GT_MetaTileEntity_ExtremeExterminationChamber( + MTEID++, "multimachine.exterminationchamber", "Extreme Extermination Chamber") + .getStackForm(1L)); + GT_ModHandler.addCraftingRecipe(ItemList.ExtremeExterminationChamber.get(1), bitsd, new Object[] { + "RCR", + "CHC", + "VVV", + 'R', + gregtech.api.enums.ItemList.Robot_Arm_EV, + 'C', + OrePrefixes.circuit.get(Materials.Data), + 'H', + gregtech.api.enums.ItemList.Hull_EV, + 'V', + GT_ModHandler.getModItem("OpenBlocks", "vacuumhopper", 1, new ItemStack(Blocks.hopper)) + }); + } + if (MTEID > MTEIDMax + 1) throw new RuntimeException("MTE ID's"); + } + + private static boolean lateRecipesInitialized = false; + + public static void addRecipesLate() { + // Runs on server start + if (lateRecipesInitialized) return; + lateRecipesInitialized = true; + + MobRecipeLoader.generateMobRecipeMap(); + MobRecipeLoader.processMobRecipeMap(); + } +} diff --git a/src/main/java/kubatech/mixin/Mixin.java b/src/main/java/kubatech/mixin/Mixin.java new file mode 100644 index 00000000..49332457 --- /dev/null +++ b/src/main/java/kubatech/mixin/Mixin.java @@ -0,0 +1,42 @@ +package kubatech.mixin; + +import static kubatech.mixin.TargetedMod.*; + +import cpw.mods.fml.relauncher.FMLLaunchHandler; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +public enum Mixin { + // Minecraft + EnchantmentHelperMixin("minecraft.EnchantmentHelperMixin", VANILLA); + + public final String mixinClass; + public final List targetedMods; + private final Side side; + + Mixin(String mixinClass, Side side, TargetedMod... targetedMods) { + this.mixinClass = mixinClass; + this.targetedMods = Arrays.asList(targetedMods); + this.side = side; + } + + Mixin(String mixinClass, TargetedMod... targetedMods) { + this.mixinClass = mixinClass; + this.targetedMods = Arrays.asList(targetedMods); + this.side = Side.BOTH; + } + + public boolean shouldLoad(List loadedMods) { + return (side == Side.BOTH + || side == Side.SERVER && FMLLaunchHandler.side().isServer() + || side == Side.CLIENT && FMLLaunchHandler.side().isClient()) + && new HashSet<>(loadedMods).containsAll(targetedMods); + } +} + +enum Side { + BOTH, + CLIENT, + SERVER +} diff --git a/src/main/java/kubatech/mixin/MixinPlugin.java b/src/main/java/kubatech/mixin/MixinPlugin.java new file mode 100644 index 00000000..66bbf9cc --- /dev/null +++ b/src/main/java/kubatech/mixin/MixinPlugin.java @@ -0,0 +1,110 @@ +package kubatech.mixin; + +import static java.nio.file.Files.walk; +import static kubatech.mixin.TargetedMod.*; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import kubatech.Tags; +import net.minecraft.launchwrapper.Launch; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.spongepowered.asm.lib.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; +import ru.timeconqueror.spongemixins.MinecraftURLClassPath; + +@SuppressWarnings("unused") +public class MixinPlugin implements IMixinConfigPlugin { + + private static final Logger LOG = LogManager.getLogger(Tags.MODID + " mixins"); + private static final Path MODS_DIRECTORY_PATH = new File(Launch.minecraftHome, "mods/").toPath(); + + @Override + public void onLoad(String mixinPackage) {} + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return false; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) {} + + @Override + public List getMixins() { + final boolean isDevelopmentEnvironment = (boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment"); + + List loadedMods = Arrays.stream(TargetedMod.values()) + .filter(mod -> mod == VANILLA || (mod.loadInDevelopment && isDevelopmentEnvironment) || loadJarOf(mod)) + .collect(Collectors.toList()); + + for (TargetedMod mod : TargetedMod.values()) { + if (loadedMods.contains(mod)) { + LOG.info("Found " + mod.modName + "! Integrating now..."); + } else { + LOG.info("Could not find " + mod.modName + "! Skipping integration...."); + } + } + + List mixins = new ArrayList<>(); + for (Mixin mixin : Mixin.values()) { + if (mixin.shouldLoad(loadedMods)) { + mixins.add(mixin.mixinClass); + LOG.debug("Loading mixin: " + mixin.mixinClass); + } + } + return mixins; + } + + private boolean loadJarOf(final TargetedMod mod) { + try { + File jar = findJarOf(mod); + if (jar == null) { + LOG.info("Jar not found for " + mod); + return false; + } + + LOG.info("Attempting to add " + jar + " to the URL Class Path"); + if (!jar.exists()) { + throw new FileNotFoundException(jar.toString()); + } + MinecraftURLClassPath.addJar(jar); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public static File findJarOf(final TargetedMod mod) { + try (Stream stream = walk(MODS_DIRECTORY_PATH)) { + return stream.filter(mod::isMatchingJar) + .map(Path::toFile) + .findFirst() + .orElse(null); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {} + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {} +} diff --git a/src/main/java/kubatech/mixin/TargetedMod.java b/src/main/java/kubatech/mixin/TargetedMod.java new file mode 100644 index 00000000..c65fadbd --- /dev/null +++ b/src/main/java/kubatech/mixin/TargetedMod.java @@ -0,0 +1,35 @@ +package kubatech.mixin; + +import com.google.common.io.Files; +import java.nio.file.Path; + +public enum TargetedMod { + VANILLA("Minecraft", "unused", true), + ; + + public final String modName; + public final String jarNamePrefixLowercase; + public final boolean loadInDevelopment; + + TargetedMod(String modName, String jarNamePrefix, boolean loadInDevelopment) { + this.modName = modName; + this.jarNamePrefixLowercase = jarNamePrefix.toLowerCase(); + this.loadInDevelopment = loadInDevelopment; + } + + @SuppressWarnings("UnstableApiUsage") + public boolean isMatchingJar(Path path) { + final String pathString = path.toString(); + final String nameLowerCase = Files.getNameWithoutExtension(pathString).toLowerCase(); + final String fileExtension = Files.getFileExtension(pathString); + + return nameLowerCase.startsWith(jarNamePrefixLowercase) && "jar".equals(fileExtension); + } + + @Override + public String toString() { + return "TargetedMod{" + "modName='" + + modName + '\'' + ", jarNamePrefixLowercase='" + + jarNamePrefixLowercase + '\'' + '}'; + } +} diff --git a/src/main/java/kubatech/mixin/mixins/minecraft/EnchantmentHelperMixin.java b/src/main/java/kubatech/mixin/mixins/minecraft/EnchantmentHelperMixin.java new file mode 100644 index 00000000..e07c0d33 --- /dev/null +++ b/src/main/java/kubatech/mixin/mixins/minecraft/EnchantmentHelperMixin.java @@ -0,0 +1,40 @@ +package kubatech.mixin.mixins.minecraft; + +import static kubatech.loaders.MobRecipeLoader.randomEnchantmentDetectedString; + +import java.util.Random; +import kubatech.api.utils.FastRandom; +import kubatech.loaders.MobRecipeLoader; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagInt; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@SuppressWarnings("unused") +@Mixin(value = EnchantmentHelper.class) +public class EnchantmentHelperMixin { + + private static final Random rnd = new FastRandom(); + + @Inject(method = "addRandomEnchantment", at = @At("HEAD"), require = 1) + private static void addRandomEnchantmentDetector( + Random random, + ItemStack itemStack, + int enchantabilityLevel, + CallbackInfoReturnable callbackInfoReturnable) { + if (MobRecipeLoader.isInGenerationProcess && random instanceof MobRecipeLoader.fakeRand) { + itemStack.setTagInfo(randomEnchantmentDetectedString, new NBTTagInt(enchantabilityLevel)); + } + } + + @ModifyVariable(method = "addRandomEnchantment", at = @At("HEAD"), ordinal = 0, argsOnly = true, require = 1) + private static Random addRandomEnchantmentModifier(Random random) { + if (!MobRecipeLoader.isInGenerationProcess) return random; + if (random instanceof MobRecipeLoader.fakeRand) return rnd; + return random; + } +} diff --git a/src/main/java/kubatech/nei/IMCForNEI.java b/src/main/java/kubatech/nei/IMCForNEI.java new file mode 100644 index 00000000..75228e19 --- /dev/null +++ b/src/main/java/kubatech/nei/IMCForNEI.java @@ -0,0 +1,76 @@ +/* + * 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 . + * + */ + +package kubatech.nei; + +import cpw.mods.fml.common.event.FMLInterModComms; +import kubatech.Tags; +import kubatech.api.LoaderReference; +import net.minecraft.nbt.NBTTagCompound; + +public class IMCForNEI { + + public static void IMCSender() { + + sendHandler("kubatech.mobhandler", "minecraft:diamond_sword", 168, 192, 1, 6); + sendCatalyst("kubatech.mobhandler", "minecraft:diamond_sword"); + if (LoaderReference.EnderIO) sendCatalyst("kubatech.mobhandler", "gregtech:gt.blockmachines:14201"); + } + + private static void sendHandler( + String aName, String aBlock, int width, int height, int maxrecipesperpage, int yshift) { + NBTTagCompound aNBT = new NBTTagCompound(); + aNBT.setString("handler", aName); + aNBT.setString("modName", Tags.MODNAME); + aNBT.setString("modId", Tags.MODID); + aNBT.setBoolean("modRequired", true); + aNBT.setString("itemName", aBlock); + aNBT.setInteger("handlerHeight", height); + aNBT.setInteger("handlerWidth", width); + aNBT.setInteger("maxRecipesPerPage", maxrecipesperpage); + aNBT.setInteger("yShift", yshift); + FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT); + } + + private static void sendGTStyledHandler(String aName, String aBlock) { + NBTTagCompound aNBT = new NBTTagCompound(); + aNBT.setString("handler", aName); + aNBT.setString("modName", Tags.MODNAME); + aNBT.setString("modId", Tags.MODID); + aNBT.setBoolean("modRequired", true); + aNBT.setString("itemName", aBlock); + aNBT.setInteger("handlerHeight", 135); + aNBT.setInteger("handlerWidth", 166); + aNBT.setInteger("maxRecipesPerPage", 2); + aNBT.setInteger("yShift", 6); + FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT); + } + + private static void sendCatalyst(String aName, String aStack, int aPriority) { + NBTTagCompound aNBT = new NBTTagCompound(); + aNBT.setString("handlerID", aName); + aNBT.setString("itemName", aStack); + aNBT.setInteger("priority", aPriority); + FMLInterModComms.sendMessage("NotEnoughItems", "registerCatalystInfo", aNBT); + } + + private static void sendCatalyst(String aName, String aStack) { + sendCatalyst(aName, aStack, 0); + } +} diff --git a/src/main/java/kubatech/nei/Mob_Handler.java b/src/main/java/kubatech/nei/Mob_Handler.java new file mode 100644 index 00000000..cd172a87 --- /dev/null +++ b/src/main/java/kubatech/nei/Mob_Handler.java @@ -0,0 +1,592 @@ +/* + * 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 . + * + */ + +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.*; +import java.util.List; +import kubatech.api.LoaderReference; +import kubatech.api.utils.FastRandom; +import kubatech.api.utils.InfernalHelper; +import kubatech.api.utils.ModUtils; +import kubatech.common.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeExterminationChamber; +import kubatech.kubatech; +import kubatech.loaders.MobRecipeLoader; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.inventory.GuiInventory; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelBox; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +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, + ; + 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; + MobRecipeLoader.MobDrop.DropType i = null; + for (MobRecipeLoader.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 == MobRecipeLoader.MobDrop.DropType.Normal) normaldrops++; + else if (d.type == MobRecipeLoader.MobDrop.DropType.Rare) raredrops++; + else if (d.type == MobRecipeLoader.MobDrop.DropType.Additional) additionaldrops++; + else if (d.type == MobRecipeLoader.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)); + } + 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(); + + ItemStack s = getIngredientStacks(recipe).get(0).item; + try { + EntityLiving e = currentrecipe.mob; + float eheight = e.height; + float ewidth = e.width; + + Render r = RenderManager.instance.getEntityRenderObject(e); + if (r instanceof RendererLivingEntity && mainmodelfield != null) { + ModelBase mainmodel = (ModelBase) mainmodelfield.get(r); + for (Object box : mainmodel.boxList) { + if (box instanceof ModelRenderer) { + float minY = 999f; + float minX = 999f; + float maxY = -999f; + float maxX = -999f; + for (Object cube : ((ModelRenderer) box).cubeList) { + if (cube instanceof ModelBox) { + if (minY > ((ModelBox) cube).posY1) minY = ((ModelBox) cube).posY1; + if (minX > ((ModelBox) cube).posX1) minX = ((ModelBox) cube).posX1; + if (maxY < ((ModelBox) cube).posY2) maxY = ((ModelBox) cube).posY2; + if (maxX < ((ModelBox) cube).posX2) maxX = ((ModelBox) cube).posX2; + } + } + float cubeheight = (maxY - minY) / 10f; + float cubewidth = (maxX - minX) / 10f; + if (eheight < cubeheight) eheight = cubeheight; + if (ewidth < cubewidth) ewidth = cubewidth; + } + } + } + + int desiredheight = 27; + int scaled = (int) (desiredheight / eheight); + // + // 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, 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 MobRecipeLoader.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, + MobRecipeLoader.MobDrop.DropType type, + int chance, + Integer enchantable, + List damages) { + 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) + "%")); + 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; + } + } +} diff --git a/src/main/java/kubatech/nei/NEI_Config.java b/src/main/java/kubatech/nei/NEI_Config.java new file mode 100644 index 00000000..8b7123a4 --- /dev/null +++ b/src/main/java/kubatech/nei/NEI_Config.java @@ -0,0 +1,44 @@ +/* + * 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 . + * + */ + +package kubatech.nei; + +import codechicken.nei.api.IConfigureNEI; +import kubatech.Tags; + +public class NEI_Config implements IConfigureNEI { + public static boolean isAdded = true; + + @Override + public void loadConfig() { + isAdded = false; + new Mob_Handler(); + isAdded = true; + } + + @Override + public String getName() { + return Tags.MODNAME + " NEI Plugin"; + } + + @Override + public String getVersion() { + return Tags.VERSION; + } +} diff --git a/src/main/java/kubatech/network/LoadConfigHandler.java b/src/main/java/kubatech/network/LoadConfigHandler.java new file mode 100644 index 00000000..a950c1d8 --- /dev/null +++ b/src/main/java/kubatech/network/LoadConfigHandler.java @@ -0,0 +1,36 @@ +/* + * 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 . + * + */ + +package kubatech.network; + +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import kubatech.kubatech; +import kubatech.loaders.MobRecipeLoader; + +public class LoadConfigHandler implements IMessageHandler { + + @Override + public IMessage onMessage(LoadConfigPacket message, MessageContext ctx) { + kubatech.info("Received Mob Handler config, parsing"); + MobRecipeLoader.processMobRecipeMap(message.mobsToLoad); + return null; + } +} diff --git a/src/main/java/kubatech/network/LoadConfigPacket.java b/src/main/java/kubatech/network/LoadConfigPacket.java new file mode 100644 index 00000000..d386d6b0 --- /dev/null +++ b/src/main/java/kubatech/network/LoadConfigPacket.java @@ -0,0 +1,61 @@ +/* + * 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 . + * + */ + +package kubatech.network; + +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import io.netty.buffer.ByteBuf; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import kubatech.Config; + +public class LoadConfigPacket implements IMessage { + + public static LoadConfigPacket instance = new LoadConfigPacket(); + + public HashSet mobsToLoad = new HashSet<>(); + + @Override + public void fromBytes(ByteBuf buf) { + if (!buf.readBoolean()) mobsToLoad.clear(); + else { + mobsToLoad.clear(); + int mobssize = buf.readInt(); + for (int i = 0; i < mobssize; i++) { + byte[] sbytes = new byte[buf.readInt()]; + buf.readBytes(sbytes); + mobsToLoad.add(new String(sbytes, StandardCharsets.UTF_8)); + } + } + } + + @Override + public void toBytes(ByteBuf buf) { + if (!Config.mobHandlerEnabled) buf.writeBoolean(false); + else { + buf.writeBoolean(true); + buf.writeInt(mobsToLoad.size()); + mobsToLoad.forEach(s -> { + byte[] sbytes = s.getBytes(StandardCharsets.UTF_8); + buf.writeInt(sbytes.length); + buf.writeBytes(sbytes); + }); + } + } +} diff --git a/src/main/resources/assets/kubatech/lang/en_US.lang b/src/main/resources/assets/kubatech/lang/en_US.lang new file mode 100644 index 00000000..be22ffc8 --- /dev/null +++ b/src/main/resources/assets/kubatech/lang/en_US.lang @@ -0,0 +1,25 @@ +#This file is a translation file for KubaTech + +#NEI +mobhandler.normal_drops=Normal drops +mobhandler.rare_drops=Rare drops +mobhandler.additional_drops=Additional drops +mobhandler.infernal_drops=Infernal drops +mobhandler.infernal_cannot=Cannot spawn infernal +mobhandler.infernal_can=Can spawn infernal +mobhandler.infernal_always=Always spawns infernal +mobhandler.mod=Mod: +mobhandler.max_health=Max health: +mobhandler.chance=Chance: +mobhandler.average_reminder=§7§oPlease remember that these are average drops. + +#Commands +commandhandler.invalid=§cInvalid use ! The proper use of this command is /%s +commandhandler.cant_find=§cCan't find command option %s +commandhandler.generic_help=§cYou can also use "/kubatech help" to get possible commands +commandhandler.usage=