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=