aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gtPlusPlus/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/gtPlusPlus/api')
-rw-r--r--src/main/java/gtPlusPlus/api/interfaces/ILazyCoverable.java139
-rw-r--r--src/main/java/gtPlusPlus/api/interfaces/IPlugin.java41
-rw-r--r--src/main/java/gtPlusPlus/api/interfaces/ITexturedBlock.java15
-rw-r--r--src/main/java/gtPlusPlus/api/interfaces/ITileTooltip.java6
-rw-r--r--src/main/java/gtPlusPlus/api/interfaces/RunnableWithInfo.java7
-rw-r--r--src/main/java/gtPlusPlus/api/objects/Logger.java162
-rw-r--r--src/main/java/gtPlusPlus/api/objects/data/AutoMap.java364
-rw-r--r--src/main/java/gtPlusPlus/api/objects/data/Pair.java35
-rw-r--r--src/main/java/gtPlusPlus/api/objects/data/Quad.java44
-rw-r--r--src/main/java/gtPlusPlus/api/objects/data/Triplet.java26
-rw-r--r--src/main/java/gtPlusPlus/api/objects/data/TypeCounter.java177
-rw-r--r--src/main/java/gtPlusPlus/api/objects/data/WeightedCollection.java102
-rw-r--r--src/main/java/gtPlusPlus/api/objects/data/weakref/WeakAutoMap.java14
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/AABB.java67
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/BTF_FluidTank.java185
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/BTF_Inventory.java231
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/BlockPos.java245
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/CubicObject.java56
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/FluidGT6.java33
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/ItemPackage.java57
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/ItemStackData.java34
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/SafeTexture.java65
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/ShapedRecipe.java251
-rw-r--r--src/main/java/gtPlusPlus/api/recipe/ChemicalPlantFrontend.java68
-rw-r--r--src/main/java/gtPlusPlus/api/recipe/GTPPRecipeCategories.java17
-rw-r--r--src/main/java/gtPlusPlus/api/recipe/GTPPRecipeMaps.java232
-rw-r--r--src/main/java/gtPlusPlus/api/recipe/MillingFrontend.java46
-rw-r--r--src/main/java/gtPlusPlus/api/recipe/TGSFrontend.java147
-rw-r--r--src/main/java/gtPlusPlus/api/recipe/ThermalBoilerFrontend.java57
29 files changed, 2923 insertions, 0 deletions
diff --git a/src/main/java/gtPlusPlus/api/interfaces/ILazyCoverable.java b/src/main/java/gtPlusPlus/api/interfaces/ILazyCoverable.java
new file mode 100644
index 0000000000..d2a1e34f99
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/interfaces/ILazyCoverable.java
@@ -0,0 +1,139 @@
+package gtPlusPlus.api.interfaces;
+
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.interfaces.tileentity.ICoverable;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+
+public interface ILazyCoverable extends ICoverable {
+
+ @Override
+ default byte getColorization() {
+ return 0;
+ }
+
+ @Override
+ default byte setColorization(byte arg0) {
+ return 0;
+ }
+
+ @Override
+ default byte getInputRedstoneSignal(ForgeDirection side) {
+ return 0;
+ }
+
+ @Override
+ default byte getStrongestRedstone() {
+ return 0;
+ }
+
+ @Override
+ default boolean getRedstone() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ default boolean getRedstone(ForgeDirection side) {
+ return false;
+ }
+
+ @Override
+ default boolean isUniversalEnergyStored(long arg0) {
+ return false;
+ }
+
+ @Override
+ default long getUniversalEnergyStored() {
+ return 0;
+ }
+
+ @Override
+ default long getUniversalEnergyCapacity() {
+ return 0;
+ }
+
+ @Override
+ default long getStoredSteam() {
+ return 0;
+ }
+
+ @Override
+ default long getSteamCapacity() {
+ return 0;
+ }
+
+ @Override
+ default boolean increaseStoredSteam(long arg0, boolean arg2) {
+ return false;
+ }
+
+ @Override
+ default byte getOutputRedstoneSignal(ForgeDirection side) {
+ return 0;
+ }
+
+ @Override
+ default void setOutputRedstoneSignal(ForgeDirection side, byte strength) {}
+
+ @Override
+ default byte getStrongOutputRedstoneSignal(ForgeDirection side) {
+ return 0;
+ }
+
+ @Override
+ default void setStrongOutputRedstoneSignal(ForgeDirection side, byte arg1) {}
+
+ @Override
+ default byte getComparatorValue(ForgeDirection side) {
+ return 0;
+ }
+
+ @Override
+ default IGregTechTileEntity getIGregTechTileEntity(int arg0, int arg1, int arg2) {
+ return null;
+ }
+
+ @Override
+ default IGregTechTileEntity getIGregTechTileEntityOffset(int arg0, int arg1, int arg2) {
+ return null;
+ }
+
+ @Override
+ default IGregTechTileEntity getIGregTechTileEntityAtSide(ForgeDirection side) {
+ return null;
+ }
+
+ @Override
+ default IGregTechTileEntity getIGregTechTileEntityAtSideAndDistance(ForgeDirection side, int arg1) {
+ return null;
+ }
+
+ @Override
+ default byte getMetaID(int arg0, int arg1, int arg2) {
+ return 0;
+ }
+
+ @Override
+ default byte getMetaIDOffset(int arg0, int arg1, int arg2) {
+ return 0;
+ }
+
+ @Override
+ default byte getMetaIDAtSide(ForgeDirection side) {
+ return 0;
+ }
+
+ @Override
+ default byte getMetaIDAtSideAndDistance(ForgeDirection side, int arg1) {
+ return 0;
+ }
+
+ @Override
+ default boolean isDead() {
+ return false;
+ }
+
+ @Override
+ default void setLightValue(byte arg0) {}
+}
diff --git a/src/main/java/gtPlusPlus/api/interfaces/IPlugin.java b/src/main/java/gtPlusPlus/api/interfaces/IPlugin.java
new file mode 100644
index 0000000000..d70a19925e
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/interfaces/IPlugin.java
@@ -0,0 +1,41 @@
+package gtPlusPlus.api.interfaces;
+
+import gtPlusPlus.api.objects.Logger;
+
+public interface IPlugin {
+
+ /**
+ * @return A {@link String} object which returns the {@link IPlugin}'s name.
+ */
+ public String getPluginName();
+
+ /**
+ * @return A {@link String} object which returns the {@link IPlugin}'s short name. This String should only contain 4
+ * Characters.
+ */
+ public String getPluginAbbreviation();
+
+ /**
+ * @param message - A {@link String} object which holds a message to be logged to console.
+ */
+ default void log(String message) {
+ Logger.INFO("[" + getPluginAbbreviation() + "] " + message);
+ }
+
+ /**
+ * @param message - A {@link String} object which holds a warning/error message to be logged to console.
+ */
+ default void logDebug(String message) {
+ Logger.WARNING("[" + getPluginAbbreviation() + "] " + message);
+ }
+
+ public boolean preInit();
+
+ public boolean init();
+
+ public boolean postInit();
+
+ public boolean serverStart();
+
+ public boolean serverStop();
+}
diff --git a/src/main/java/gtPlusPlus/api/interfaces/ITexturedBlock.java b/src/main/java/gtPlusPlus/api/interfaces/ITexturedBlock.java
new file mode 100644
index 0000000000..a6179ce2bf
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/interfaces/ITexturedBlock.java
@@ -0,0 +1,15 @@
+package gtPlusPlus.api.interfaces;
+
+import net.minecraft.block.Block;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.tileentity.ITexturedTileEntity;
+
+public interface ITexturedBlock extends ITexturedTileEntity {
+
+ ITexture[] getTexture(ForgeDirection side);
+
+ @Override
+ ITexture[] getTexture(Block block, ForgeDirection side);
+}
diff --git a/src/main/java/gtPlusPlus/api/interfaces/ITileTooltip.java b/src/main/java/gtPlusPlus/api/interfaces/ITileTooltip.java
new file mode 100644
index 0000000000..f059ef8a5f
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/interfaces/ITileTooltip.java
@@ -0,0 +1,6 @@
+package gtPlusPlus.api.interfaces;
+
+public interface ITileTooltip {
+
+ int getTooltipID();
+}
diff --git a/src/main/java/gtPlusPlus/api/interfaces/RunnableWithInfo.java b/src/main/java/gtPlusPlus/api/interfaces/RunnableWithInfo.java
new file mode 100644
index 0000000000..f00287404b
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/interfaces/RunnableWithInfo.java
@@ -0,0 +1,7 @@
+package gtPlusPlus.api.interfaces;
+
+public interface RunnableWithInfo<V> extends Runnable {
+
+ V getInfoData();
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/Logger.java b/src/main/java/gtPlusPlus/api/objects/Logger.java
new file mode 100644
index 0000000000..0178bb141a
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/Logger.java
@@ -0,0 +1,162 @@
+package gtPlusPlus.api.objects;
+
+import org.apache.logging.log4j.LogManager;
+
+import cpw.mods.fml.common.FMLLog;
+import cpw.mods.fml.relauncher.FMLRelaunchLog;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.preloader.CORE_Preloader;
+import gtPlusPlus.preloader.asm.AsmConfig;
+
+public class Logger {
+
+ public Logger() {}
+
+ // Logging Functions
+ public static final org.apache.logging.log4j.Logger modLogger = Logger.makeLogger();
+
+ // Generate GT++ Logger
+ public static org.apache.logging.log4j.Logger makeLogger() {
+ final org.apache.logging.log4j.Logger gtPlusPlusLogger = LogManager.getLogger("GT++");
+ return gtPlusPlusLogger;
+ }
+
+ private static final boolean enabled = !AsmConfig.disableAllLogging;
+
+ public static final org.apache.logging.log4j.Logger getLogger() {
+ return modLogger;
+ }
+
+ // Non-Dev Comments
+ public static void INFO(final String s) {
+ if (enabled) {
+ modLogger.info(s);
+ }
+ }
+
+ // Non-Dev Comments
+ public static void MACHINE_INFO(String s, Object... args) {
+ if (enabled) {
+ boolean localPlayer = CORE_Preloader.DEV_ENVIRONMENT;
+ if (CORE.ConfigSwitches.MACHINE_INFO || localPlayer) {
+ final String name1 = gtPlusPlus.core.util.reflect.ReflectionUtils.getMethodName(2);
+ modLogger.info("Machine Info: " + s + " | " + name1, args);
+ }
+ }
+ }
+
+ // Developer Comments
+ public static void WARNING(final String s) {
+ if (enabled) {
+ if (CORE_Preloader.DEBUG_MODE) {
+ modLogger.warn(s);
+ }
+ }
+ }
+
+ // Errors
+ public static void ERROR(final String s) {
+ if (enabled) {
+ if (CORE_Preloader.DEBUG_MODE) {
+ modLogger.fatal(s);
+ }
+ }
+ }
+
+ // Developer Logger
+ public static void SPECIFIC_WARNING(final String whatToLog, final String msg, final int line) {
+ if (enabled) {
+ // if (!CORE_Preloader.DEBUG_MODE){
+ FMLLog.warning("GT++ |" + line + "| " + whatToLog + " | " + msg);
+ // }
+ }
+ }
+
+ // ASM Comments
+ public static void LOG_ASM(final String s) {
+ if (enabled) {
+ FMLRelaunchLog.info("[Special ASM Logging] ", s);
+ }
+ }
+
+ /**
+ * Special Loggers
+ */
+
+ /**
+ * Special Logger for Bee related content
+ */
+ public static void BEES(final String s) {
+ modLogger.info("[Bees] " + s);
+ }
+
+ /**
+ * Special Logger for Debugging Bee related content
+ */
+ public static void DEBUG_BEES(final String s) {
+ if (enabled) {
+ if (CORE_Preloader.DEV_ENVIRONMENT || CORE_Preloader.DEBUG_MODE) {
+ modLogger.info("[Debug][Bees] " + s);
+ }
+ }
+ }
+
+ /**
+ * Special Logger for Materials related content
+ */
+ public static void MATERIALS(final String s) {
+ if (enabled) {
+ if (CORE_Preloader.DEV_ENVIRONMENT || CORE_Preloader.DEBUG_MODE) {
+ modLogger.info("[Materials] " + s);
+ }
+ }
+ }
+
+ /**
+ * Special Logger for Debugging Materials related content
+ */
+ public static void DEBUG_MATERIALS(final String s) {
+ if (enabled) {
+ if (CORE_Preloader.DEV_ENVIRONMENT || CORE_Preloader.DEBUG_MODE) {
+ modLogger.info("[Debug][Materials] " + s);
+ }
+ }
+ }
+
+ /**
+ * Special Logger for Reflection related content
+ */
+ public static void REFLECTION(final String s) {
+ if (enabled) {
+ if (CORE_Preloader.DEV_ENVIRONMENT || CORE_Preloader.DEBUG_MODE) {
+ modLogger.info("[Reflection] " + s);
+ }
+ }
+ }
+
+ /**
+ * Special Logger for Darkworld related content
+ */
+ public static void WORLD(final String s) {
+ if (enabled) {
+ if (CORE_Preloader.DEV_ENVIRONMENT || CORE_Preloader.DEBUG_MODE) {
+ modLogger.info("[WorldGen] " + s);
+ }
+ }
+ }
+
+ public static void RECIPE(String string) {
+ if (enabled) {
+ if (
+ /* CORE_Preloader.DEV_ENVIRONMENT || */ CORE_Preloader.DEBUG_MODE) {
+ modLogger.info("[Recipe] " + string);
+ }
+ }
+ }
+
+ public static void SPACE(final String s) {
+ if (enabled) {
+ modLogger.info("[Space] " + s);
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/data/AutoMap.java b/src/main/java/gtPlusPlus/api/objects/data/AutoMap.java
new file mode 100644
index 0000000000..a3551326c2
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/data/AutoMap.java
@@ -0,0 +1,364 @@
+package gtPlusPlus.api.objects.data;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+public class AutoMap<V> implements Iterable<V>, Cloneable, Serializable, Collection<V>, Queue<V>, List<V> {
+
+ /**
+ * The Internal Map
+ */
+ protected final Map<Integer, V> mInternalMap;
+
+ protected final Map<String, Integer> mInternalNameMap;
+
+ /**
+ * The Internal ID
+ */
+ private int mInternalID = 0;
+
+ private static final long serialVersionUID = 3771412318075131790L;
+
+ public AutoMap() {
+ this(new LinkedHashMap<>());
+ }
+
+ public Map<Integer, V> getMap() {
+ return mInternalMap;
+ }
+
+ public AutoMap(Map<Integer, V> defaultMapType) {
+ mInternalMap = defaultMapType;
+ mInternalNameMap = new LinkedHashMap<>();
+ }
+
+ /**
+ * Generates an AutoMap from the List.
+ *
+ * @param aList - Data to be inserted into the AutoMap.
+ */
+ public AutoMap(List<V> aList) {
+ mInternalMap = new LinkedHashMap<>();
+ mInternalNameMap = new LinkedHashMap<>();
+ if (aList != null && aList.size() > 0) {
+ for (V obj : aList) {
+ add(obj);
+ }
+ }
+ }
+
+ /**
+ * Generates an AutoMap from a Set.
+ *
+ * @param aList - Data to be inserted into the AutoMap.
+ */
+ public AutoMap(Set<V> aList) {
+ mInternalMap = new LinkedHashMap<>();
+ mInternalNameMap = new LinkedHashMap<>();
+ if (aList != null && aList.size() > 0) {
+ for (V obj : aList) {
+ add(obj);
+ }
+ }
+ }
+
+ /**
+ * Generates an AutoMap from a Collection.
+ *
+ * @param aList - Data to be inserted into the AutoMap.
+ */
+ public AutoMap(Collection<V> aList) {
+ mInternalMap = new LinkedHashMap<>();
+ mInternalNameMap = new LinkedHashMap<>();
+ if (aList != null && aList.size() > 0) {
+ for (V obj : aList) {
+ add(obj);
+ }
+ }
+ }
+
+ /**
+ * Generates an AutoMap from a Array.
+ *
+ * @param aArray - Data to be inserted into the AutoMap.
+ */
+ public AutoMap(V[] aArray) {
+ mInternalMap = new LinkedHashMap<>();
+ mInternalNameMap = new LinkedHashMap<>();
+ if (aArray != null && aArray.length > 0) {
+ for (V obj : aArray) {
+ add(obj);
+ }
+ }
+ }
+
+ @Override
+ public Iterator<V> iterator() {
+ return values().iterator();
+ }
+
+ public synchronized boolean setValue(V object) {
+ int mOriginalID = this.mInternalID;
+ put(object);
+ if (this.mInternalMap.get(mOriginalID)
+ .equals(object) || mOriginalID > this.mInternalID) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public synchronized V put(V object) {
+ return set(object);
+ }
+
+ @Override
+ public synchronized boolean add(V object) {
+ return set(object) != null;
+ }
+
+ public synchronized V set(V object) {
+ if (object == null) {
+ return null;
+ }
+ mInternalNameMap.put("" + object.hashCode(), (mInternalID + 1));
+ return mInternalMap.put(mInternalID++, object);
+ }
+
+ @Override
+ public synchronized V get(int id) {
+ return mInternalMap.get(id);
+ }
+
+ public synchronized Collection<V> values() {
+ return mInternalMap.values();
+ }
+
+ @Override
+ public synchronized int size() {
+ return mInternalMap.size();
+ }
+
+ public synchronized int hashCode() {
+ return mInternalMap.hashCode();
+ }
+
+ public synchronized boolean containsKey(int key) {
+ return mInternalMap.containsKey(key);
+ }
+
+ public synchronized boolean containsValue(V value) {
+ return mInternalMap.containsValue(value);
+ }
+
+ @Override
+ public synchronized boolean isEmpty() {
+ return mInternalMap.isEmpty();
+ }
+
+ @Override
+ public synchronized void clear() {
+ this.mInternalID = 0;
+ this.mInternalMap.clear();
+ this.mInternalNameMap.clear();
+ return;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public V[] toArray() {
+ V[] toR = (V[]) java.lang.reflect.Array.newInstance(
+ mInternalMap.get(0)
+ .getClass(),
+ mInternalMap.size());
+ for (int i = 0; i < mInternalMap.size(); i++) {
+ toR[i] = mInternalMap.get(i);
+ }
+ return toR;
+ }
+
+ public final synchronized int getInternalID() {
+ return mInternalID;
+ }
+
+ @Override
+ public final synchronized boolean remove(Object value) {
+ value.getClass();
+ if (this.mInternalMap.containsValue(value)) {
+ return this.mInternalMap.remove(mInternalNameMap.get("" + value.hashCode()), value);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ for (V g : this.mInternalMap.values()) {
+ if (g.equals(o)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <V> V[] toArray(V[] a) {
+ return (V[]) toArray();
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ boolean aTrue = true;
+ for (Object g : c) {
+ if (!this.contains(g)) {
+ aTrue = false;
+ }
+ }
+ return aTrue;
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends V> c) {
+ boolean aTrue = true;
+ for (V g : c) {
+ if (!this.add(g)) {
+ aTrue = false;
+ }
+ }
+ return aTrue;
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ boolean aTrue = true;
+ for (Object g : c) {
+ if (!this.remove(g)) {
+ aTrue = false;
+ }
+ }
+ return aTrue;
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ AutoMap<?> aTempAllocation = new AutoMap<>();
+ boolean aTrue = false;
+ aTempAllocation = this;
+ aTempAllocation.removeAll(c);
+ aTempAllocation.clear();
+ aTrue = aTempAllocation.isEmpty();
+ aTempAllocation.clear();
+ return aTrue;
+ }
+
+ @Override
+ public boolean offer(V e) {
+ return add(e);
+ }
+
+ @Override
+ public V remove() {
+ V y = this.get(0);
+ if (remove(y)) return y;
+ else return null;
+ }
+
+ @Override
+ public V poll() {
+ if (this.mInternalMap.isEmpty()) {
+ return null;
+ }
+ return remove();
+ }
+
+ @Override
+ public V element() {
+ if (this.mInternalMap.isEmpty()) {
+ return null;
+ }
+ return this.get(0);
+ }
+
+ @Override
+ public V peek() {
+ return element();
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends V> c) {
+ for (V y : c) {
+ add(y);
+ }
+ return true;
+ }
+
+ @Override
+ public V set(int index, V element) {
+ return mInternalMap.put(index, element);
+ }
+
+ @Override
+ public void add(int index, V element) {
+ add(element);
+ }
+
+ @Override
+ public V remove(int index) {
+ V h = mInternalMap.get(index);
+ set(index, null);
+ return h;
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ int aCount = 0;
+ for (V of : mInternalMap.values()) {
+ if (of != o) {
+ aCount++;
+ continue;
+ } else {
+ return aCount;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ // TODO
+ return indexOf(o);
+ }
+
+ @Override
+ public ListIterator<V> listIterator() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ListIterator<V> listIterator(int index) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<V> subList(int fromIndex, int toIndex) {
+ AutoMap<V> aNewSubList = new AutoMap<>();
+ for (int slot = fromIndex; slot <= toIndex; slot++) {
+ V obj = mInternalMap.get(slot);
+ if (obj == null) {
+ continue;
+ } else {
+ aNewSubList.put(obj);
+ }
+ }
+ return aNewSubList;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/data/Pair.java b/src/main/java/gtPlusPlus/api/objects/data/Pair.java
new file mode 100644
index 0000000000..93bf075c8f
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/data/Pair.java
@@ -0,0 +1,35 @@
+package gtPlusPlus.api.objects.data;
+
+import java.io.Serializable;
+
+import com.google.common.base.Objects;
+
+public class Pair<K, V> implements Serializable {
+
+ /**
+ * SVUID
+ */
+ private static final long serialVersionUID = 1250550491092812443L;
+
+ private final K key;
+ private final V value;
+
+ public Pair(final K key, final V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public final K getKey() {
+ return this.key;
+ }
+
+ public final V getValue() {
+ return this.value;
+ }
+
+ @Override
+ public int hashCode() {
+ Integer aCode = Objects.hashCode(getKey(), getValue());
+ return aCode != null ? aCode : super.hashCode();
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/data/Quad.java b/src/main/java/gtPlusPlus/api/objects/data/Quad.java
new file mode 100644
index 0000000000..a2597061e0
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/data/Quad.java
@@ -0,0 +1,44 @@
+package gtPlusPlus.api.objects.data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Quad<K, V, C, R> {
+
+ private final K key;
+ private final V value;
+ private final C value2;
+ private final R value3;
+
+ public Quad(final K key, final V value, final C value2, final R value3) {
+ this.key = key;
+ this.value = value;
+ this.value2 = value2;
+ this.value3 = value3;
+ }
+
+ public final K getKey() {
+ return this.key;
+ }
+
+ public final V getValue_1() {
+ return this.value;
+ }
+
+ public final C getValue_2() {
+ return this.value2;
+ }
+
+ public final R getValue_3() {
+ return this.value3;
+ }
+
+ public final List values() {
+ List<Object> aVals = new ArrayList<>();
+ aVals.add(key);
+ aVals.add(value);
+ aVals.add(value2);
+ aVals.add(value3);
+ return aVals;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/data/Triplet.java b/src/main/java/gtPlusPlus/api/objects/data/Triplet.java
new file mode 100644
index 0000000000..625ec630aa
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/data/Triplet.java
@@ -0,0 +1,26 @@
+package gtPlusPlus.api.objects.data;
+
+public class Triplet<K, V, C> {
+
+ private final K key;
+ private final V value;
+ private final C count;
+
+ public Triplet(final K key, final V value, final C value2) {
+ this.key = key;
+ this.value = value;
+ this.count = value2;
+ }
+
+ public final K getValue_1() {
+ return this.key;
+ }
+
+ public final V getValue_2() {
+ return this.value;
+ }
+
+ public final C getValue_3() {
+ return this.count;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/data/TypeCounter.java b/src/main/java/gtPlusPlus/api/objects/data/TypeCounter.java
new file mode 100644
index 0000000000..ea12972af4
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/data/TypeCounter.java
@@ -0,0 +1,177 @@
+package gtPlusPlus.api.objects.data;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import gtPlusPlus.api.objects.Logger;
+
+public class TypeCounter<V> implements Set<V> {
+
+ private Map<String, InternalTypeCounterObject<V>> mInternalMap = new LinkedHashMap<>();
+ private String mHighestValueKey;
+ private int mHighestValue = 0;
+ private final Class mClass;
+
+ public TypeCounter(Class o) {
+ Logger.WARNING("Created new TypeCounter for " + o.getName());
+ mClass = o;
+ }
+
+ public static class InternalTypeCounterObject<Z> {
+
+ private final Z mObject;
+ private int mCounter = 0;
+
+ public InternalTypeCounterObject(Z o) {
+ mObject = o;
+ }
+
+ public String hash() {
+ return String.valueOf(mObject.hashCode());
+ }
+
+ public Z get() {
+ return mObject;
+ }
+
+ public void add() {
+ mCounter++;
+ }
+
+ public int count() {
+ return mCounter;
+ }
+ }
+
+ @Override
+ public boolean add(V arg0) {
+ return add(arg0, null);
+ }
+
+ public boolean add(V arg0, String aKeyName) {
+ String aKey = aKeyName != null ? aKeyName : arg0.toString();
+ InternalTypeCounterObject<V> aValue = mInternalMap.get(aKey);
+ if (aValue == null) {
+ aValue = new InternalTypeCounterObject<>((V) arg0);
+ Logger.WARNING("Adding new key to map: " + aKey);
+ }
+ aValue.add();
+ int a = aValue.count();
+ if (a > mHighestValue) {
+ mHighestValue = a;
+ mHighestValueKey = aKey;
+ Logger.WARNING("New Highest Count - " + aKey + ":" + a);
+ }
+ mInternalMap.put(aKey, aValue);
+ Logger.WARNING(aKey + ":" + a);
+ return true;
+ }
+
+ @Override
+ public boolean addAll(Collection arg0) {
+ boolean aReturn = true;
+ for (Object o : arg0) {
+ if (mClass.isInstance(o)) {
+ V j = (V) o;
+ boolean b = add(j);
+ if (!b) {
+ aReturn = false;
+ }
+ }
+ }
+ return aReturn;
+ }
+
+ @Override
+ public void clear() {
+ mInternalMap.clear();
+ }
+
+ @Override
+ public boolean contains(Object arg0) {
+ return mInternalMap.containsKey(arg0.toString());
+ }
+
+ @Override
+ public boolean containsAll(Collection arg0) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return mInternalMap.isEmpty();
+ }
+
+ @Override
+ public Iterator iterator() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean remove(Object arg0) {
+ InternalTypeCounterObject<V> aValue = mInternalMap.remove(arg0.toString());
+ if (aValue != null) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean removeAll(Collection arg0) {
+ boolean aReturn = true;
+ for (Object o : arg0) {
+ boolean a = remove(o);
+ if (!a) {
+ aReturn = false;
+ }
+ }
+ return aReturn;
+ }
+
+ @Override
+ public boolean retainAll(Collection arg0) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public int size() {
+ return this.mInternalMap.size();
+ }
+
+ @Override
+ public Object[] toArray() {
+ Object[] aArray = new Object[this.mInternalMap.size()];
+ int aPos = 0;
+ for (String k : this.mInternalMap.keySet()) {
+ if (k != null) {
+ InternalTypeCounterObject<V> aVal = this.mInternalMap.get(k);
+ aArray[aPos++] = new Pair<>(k, aVal);
+ }
+ }
+ return aArray;
+ }
+
+ @Override
+ public V[] toArray(Object[] a) {
+ Object[] aArray = new Object[a.length];
+ int aPos = 0;
+ for (Object k : a) {
+ if (k != null) {
+ aArray[aPos++] = k;
+ }
+ }
+ return (V[]) aArray;
+ }
+
+ public V getResults() {
+ InternalTypeCounterObject<V> x = mInternalMap.get(mHighestValueKey);
+ return x.get();
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/data/WeightedCollection.java b/src/main/java/gtPlusPlus/api/objects/data/WeightedCollection.java
new file mode 100644
index 0000000000..5d99097169
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/data/WeightedCollection.java
@@ -0,0 +1,102 @@
+package gtPlusPlus.api.objects.data;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.Random;
+import java.util.Set;
+import java.util.TreeMap;
+
+import gregtech.api.objects.XSTR;
+
+public class WeightedCollection<E> implements Map<Integer, E> {
+
+ private NavigableMap<Integer, E> map = new TreeMap<>();
+ private Random random;
+ private int total = 0;
+
+ public WeightedCollection() {
+ this(new XSTR());
+ }
+
+ public WeightedCollection(Random random) {
+ this.random = random;
+ }
+
+ public E add(int weight, E object) {
+ if (weight <= 0) return null;
+ total += weight;
+ return map.put(total, object);
+ }
+
+ private E next() {
+ int value = random.nextInt(total) + 1; // Can also use floating-point weights
+ return map.ceilingEntry(value)
+ .getValue();
+ }
+
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return map.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return map.containsValue(value);
+ }
+
+ public E get() {
+ return next();
+ }
+
+ @Override
+ public E get(Object key) {
+ return next();
+ }
+
+ @Override
+ public void putAll(Map m) {
+ map.putAll(m);
+ }
+
+ @Override
+ public void clear() {
+ map.clear();
+ this.total = 0;
+ }
+
+ @Override
+ public Set keySet() {
+ return map.keySet();
+ }
+
+ @Override
+ public Collection values() {
+ return map.values();
+ }
+
+ @Override
+ public Set entrySet() {
+ return map.entrySet();
+ }
+
+ @Override
+ public E put(Integer key, E value) {
+ return add(key, value);
+ }
+
+ @Override
+ public E remove(Object key) {
+ return map.remove(key);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/data/weakref/WeakAutoMap.java b/src/main/java/gtPlusPlus/api/objects/data/weakref/WeakAutoMap.java
new file mode 100644
index 0000000000..199d20e06a
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/data/weakref/WeakAutoMap.java
@@ -0,0 +1,14 @@
+package gtPlusPlus.api.objects.data.weakref;
+
+import java.util.WeakHashMap;
+
+import gtPlusPlus.api.objects.data.AutoMap;
+
+public class WeakAutoMap<T> extends AutoMap<T> {
+
+ private static final long serialVersionUID = 8328345351801363386L;
+
+ public WeakAutoMap() {
+ super(new WeakHashMap<>());
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/AABB.java b/src/main/java/gtPlusPlus/api/objects/minecraft/AABB.java
new file mode 100644
index 0000000000..e516f12ddd
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/AABB.java
@@ -0,0 +1,67 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import net.minecraft.entity.Entity;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.world.World;
+
+import gtPlusPlus.core.util.minecraft.EntityUtils;
+
+/**
+ * Generates an AABB around an entity.
+ *
+ * @author Alkalus
+ *
+ */
+public class AABB {
+
+ private final AxisAlignedBB mAabb;
+ private final World mWorld;
+
+ /**
+ * Creates a AxisAlignedBB based around an Entity.
+ *
+ * @param aEntity - The Entity to work with.
+ * @param x - Maximum X from origin.
+ * @param y - Maximum Y from origin.
+ * @param z - Maximum Z from origin.
+ */
+ public AABB(Entity aEntity, int x, int y, int z) {
+ if (aEntity == null) {
+ mAabb = null;
+ mWorld = null;
+ } else {
+ mWorld = aEntity.worldObj;
+ BlockPos aEntityLocation = EntityUtils.findBlockPosUnderEntity(aEntity);
+ int xMin, xMax, yMin, yMax, zMin, zMax;
+ xMin = aEntityLocation.xPos;
+ yMin = aEntityLocation.yPos;
+ zMin = aEntityLocation.zPos;
+ xMax = aEntityLocation.xPos + x;
+ yMax = aEntityLocation.yPos + y;
+ zMax = aEntityLocation.zPos + z;
+ mAabb = AxisAlignedBB.getBoundingBox(xMin, yMin, zMin, xMax, yMax, zMax);
+ }
+ }
+
+ /**
+ * Used to get the AxisAlignedBB from this class.
+ *
+ * @return
+ */
+ public AxisAlignedBB get() {
+ return mAabb;
+ }
+
+ /**
+ * Used to determine if this object is valid or not.
+ *
+ * @return
+ */
+ public boolean valid() {
+ return mAabb != null && mWorld != null;
+ }
+
+ public World world() {
+ return mWorld;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_FluidTank.java b/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_FluidTank.java
new file mode 100644
index 0000000000..13f12503f0
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_FluidTank.java
@@ -0,0 +1,185 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.FluidTank;
+import net.minecraftforge.fluids.FluidTankInfo;
+
+public class BTF_FluidTank extends FluidTank {
+
+ public FluidStack mFluid;
+
+ public BTF_FluidTank(int capacity) {
+ super(capacity);
+ }
+
+ /**
+ * Let's replace the Default handling with GT's own handling code, because it's probably better, right?
+ *
+ * @author Alkalus/GregoriusT
+ */
+ @Override
+ public FluidStack getFluid() {
+ return this.getDrainableStack();
+ }
+
+ @Override
+ public int getFluidAmount() {
+ return this.getDrainableStack() != null ? this.getDrainableStack().amount : 0;
+ }
+
+ @Override
+ public NBTTagCompound writeToNBT(NBTTagCompound aNBT) {
+ super.writeToNBT(aNBT);
+ if (this.mFluid != null) {
+ aNBT.setTag("mFluid", this.mFluid.writeToNBT(new NBTTagCompound()));
+ }
+ return aNBT;
+ }
+
+ @Override
+ public FluidTank readFromNBT(NBTTagCompound aNBT) {
+ this.mFluid = FluidStack.loadFluidStackFromNBT(aNBT.getCompoundTag("mFluid"));
+ return this;
+ }
+
+ /*
+ * public abstract boolean isLiquidInput(byte arg0); public abstract boolean isLiquidOutput(byte arg0); public
+ * abstract boolean doesFillContainers(); public abstract boolean doesEmptyContainers();
+ */
+
+ public boolean canTankBeFilled() {
+ return true;
+ }
+
+ public boolean canTankBeEmptied() {
+ return true;
+ }
+
+ public boolean isFluidInputAllowed(FluidStack aFluid) {
+ return true;
+ }
+
+ public FluidStack getFillableStack() {
+ return this.mFluid;
+ }
+
+ public FluidStack setFillableStack(FluidStack aFluid) {
+ this.mFluid = aFluid;
+ return this.mFluid;
+ }
+
+ public FluidStack getDrainableStack() {
+ return this.mFluid;
+ }
+
+ public FluidStack setDrainableStack(FluidStack aFluid) {
+ this.mFluid = aFluid;
+ return this.mFluid;
+ }
+
+ public boolean isFluidChangingAllowed() {
+ return true;
+ }
+
+ @Override
+ public int fill(FluidStack aFluid, boolean doFill) {
+ if (aFluid != null && aFluid.getFluid()
+ .getID() > 0 && aFluid.amount > 0 && this.canTankBeFilled() && this.isFluidInputAllowed(aFluid)) {
+ if (this.getFillableStack() != null && this.getFillableStack()
+ .getFluid()
+ .getID() > 0) {
+ if (!this.getFillableStack()
+ .isFluidEqual(aFluid)) {
+ return 0;
+ } else {
+ int space = this.getCapacity() - this.getFillableStack().amount;
+ if (aFluid.amount <= space) {
+ if (doFill) {
+ FluidStack arg9999 = this.getFillableStack();
+ arg9999.amount += aFluid.amount;
+ }
+
+ return aFluid.amount;
+ } else {
+ if (doFill) {
+ this.getFillableStack().amount = this.getCapacity();
+ }
+
+ return space;
+ }
+ }
+ } else if (aFluid.amount <= this.getCapacity()) {
+ if (doFill) {
+ this.setFillableStack(aFluid.copy());
+ }
+
+ return aFluid.amount;
+ } else {
+ if (doFill) {
+ this.setFillableStack(aFluid.copy());
+ this.getFillableStack().amount = this.getCapacity();
+ }
+
+ return this.getCapacity();
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public FluidStack drain(int maxDrain, boolean doDrain) {
+ if (this.getDrainableStack() != null && this.canTankBeEmptied()) {
+ if (this.getDrainableStack().amount <= 0 && this.isFluidChangingAllowed()) {
+ this.setDrainableStack((FluidStack) null);
+ return null;
+ } else {
+ int used = maxDrain;
+ if (this.getDrainableStack().amount < maxDrain) {
+ used = this.getDrainableStack().amount;
+ }
+
+ if (doDrain) {
+ FluidStack arg9999 = this.getDrainableStack();
+ arg9999.amount -= used;
+ }
+
+ FluidStack drained = this.getDrainableStack()
+ .copy();
+ drained.amount = used;
+ if (this.getDrainableStack().amount <= 0 && this.isFluidChangingAllowed()) {
+ this.setDrainableStack((FluidStack) null);
+ }
+
+ return drained;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int getCapacity() {
+ return super.getCapacity();
+ }
+
+ @Override
+ public FluidTankInfo getInfo() {
+ return new FluidTankInfo(this);
+ }
+
+ @Override
+ public void setFluid(FluidStack fluid) {
+ setFillableStack(fluid);
+ }
+
+ @Override
+ public void setCapacity(int capacity) {
+ super.setCapacity(capacity);
+ }
+
+ public FluidStack drain(FluidStack aFluid, boolean doDrain) {
+ return drain(aFluid.amount, doDrain);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_Inventory.java b/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_Inventory.java
new file mode 100644
index 0000000000..fc71869d9e
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_Inventory.java
@@ -0,0 +1,231 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import java.util.ArrayList;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.inventory.ISidedInventory;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.util.GT_Utility;
+import gregtech.common.covers.CoverInfo;
+import gtPlusPlus.core.tileentities.base.TileEntityBase;
+import gtPlusPlus.core.util.data.ArrayUtils;
+
+public class BTF_Inventory implements ISidedInventory {
+
+ public final ItemStack[] mInventory;
+ public final TileEntityBase mTile;
+
+ public BTF_Inventory(int aSlots, TileEntityBase tile) {
+ this.mInventory = new ItemStack[aSlots];
+ this.mTile = tile;
+ }
+
+ public ItemStack[] getRealInventory() {
+ purgeNulls();
+ return this.mInventory;
+ }
+
+ @Override
+ public int getSizeInventory() {
+ return this.mInventory.length;
+ }
+
+ @Override
+ public ItemStack getStackInSlot(int aIndex) {
+ return aIndex >= 0 && aIndex < this.mInventory.length ? this.mInventory[aIndex] : null;
+ }
+
+ @Override
+ public void setInventorySlotContents(int aIndex, ItemStack aStack) {
+ if (aIndex >= 0 && aIndex < this.mInventory.length) {
+ this.mInventory[aIndex] = aStack;
+ }
+ }
+
+ public boolean isAccessAllowed(EntityPlayer aPlayer) {
+ return true;
+ }
+
+ public boolean isValidSlot(int aIndex) {
+ return true;
+ }
+
+ @Override
+ public int getInventoryStackLimit() {
+ return 64;
+ }
+
+ public boolean setStackToZeroInsteadOfNull(int aIndex) {
+ return false;
+ }
+
+ @Override
+ public boolean isItemValidForSlot(int aIndex, ItemStack aStack) {
+ return isValidSlot(aIndex);
+ }
+
+ @Override
+ public ItemStack decrStackSize(int aIndex, int aAmount) {
+ ItemStack tStack = this.getStackInSlot(aIndex);
+ ItemStack rStack = GT_Utility.copy(new Object[] { tStack });
+ if (tStack != null) {
+ if (tStack.stackSize <= aAmount) {
+ if (this.setStackToZeroInsteadOfNull(aIndex)) {
+ tStack.stackSize = 0;
+ } else {
+ this.setInventorySlotContents(aIndex, (ItemStack) null);
+ }
+ } else {
+ rStack = tStack.splitStack(aAmount);
+ if (tStack.stackSize == 0 && !this.setStackToZeroInsteadOfNull(aIndex)) {
+ this.setInventorySlotContents(aIndex, (ItemStack) null);
+ }
+ }
+ }
+
+ return rStack;
+ }
+
+ @Override
+ public int[] getAccessibleSlotsFromSide(int ordinalSide) {
+ final ForgeDirection side = ForgeDirection.getOrientation(ordinalSide);
+ ArrayList<Integer> tList = new ArrayList<>();
+ CoverInfo coverInfo = this.mTile.getCoverInfoAtSide(side);
+ boolean tSkip = coverInfo.letsItemsIn(-2) || coverInfo.letsItemsIn(-2);
+
+ for (int rArray = 0; rArray < this.getSizeInventory(); ++rArray) {
+ if (this.isValidSlot(rArray)
+ && (tSkip || coverInfo.letsItemsOut(rArray) || coverInfo.letsItemsIn(rArray))) {
+ tList.add(rArray);
+ }
+ }
+
+ int[] arg6 = new int[tList.size()];
+
+ for (int i = 0; i < arg6.length; ++i) {
+ arg6[i] = tList.get(i);
+ }
+
+ return arg6;
+ }
+
+ @Override
+ public boolean canInsertItem(int aIndex, ItemStack aStack, int ordinalSide) {
+ return this.isValidSlot(aIndex) && aStack != null
+ && aIndex < this.mInventory.length
+ && (this.mInventory[aIndex] == null || GT_Utility.areStacksEqual(aStack, this.mInventory[aIndex]))
+ && this.allowPutStack(this.mTile, aIndex, ForgeDirection.getOrientation(ordinalSide), aStack);
+ }
+
+ @Override
+ public boolean canExtractItem(int aIndex, ItemStack aStack, int ordinalSide) {
+ return this.isValidSlot(aIndex) && aStack != null
+ && aIndex < this.mInventory.length
+ && this.allowPullStack(this.mTile, aIndex, ForgeDirection.getOrientation(ordinalSide), aStack);
+ }
+
+ public boolean allowPullStack(TileEntityBase mTile2, int aIndex, ForgeDirection side, ItemStack aStack) {
+ return aIndex >= 0 && aIndex < this.getSizeInventory();
+ }
+
+ public boolean allowPutStack(TileEntityBase aBaseMetaTileEntity, int aIndex, ForgeDirection side,
+ ItemStack aStack) {
+ return (aIndex >= 0 && aIndex < this.getSizeInventory())
+ && (this.mInventory[aIndex] == null || GT_Utility.areStacksEqual(this.mInventory[aIndex], aStack));
+ }
+
+ @Override
+ public ItemStack getStackInSlotOnClosing(int i) {
+ return null;
+ }
+
+ @Override
+ public final boolean hasCustomInventoryName() {
+ return mTile != null ? mTile.hasCustomInventoryName() : false;
+ }
+
+ @Override
+ public void markDirty() {
+ if (mTile != null) {
+ purgeNulls();
+ mTile.markDirty();
+ }
+ }
+
+ @Override
+ public boolean isUseableByPlayer(EntityPlayer entityplayer) {
+ return true;
+ }
+
+ @Override
+ public void openInventory() {}
+
+ @Override
+ public void closeInventory() {}
+
+ @Override
+ public final String getInventoryName() {
+ return this.mTile != null ? mTile.getInventoryName() : "";
+ }
+
+ public boolean isFull() {
+ for (int s = 0; s < this.getSizeInventory(); s++) {
+ ItemStack slot = mInventory[s];
+ if (slot == null || slot.stackSize != slot.getMaxStackSize()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isEmpty() {
+ for (int s = 0; s < this.getSizeInventory(); s++) {
+ ItemStack slot = mInventory[s];
+ if (slot == null) {
+ continue;
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean addItemStack(ItemStack aInput) {
+ if (aInput != null & (isEmpty() || !isFull())) {
+ for (int s = 0; s < this.getSizeInventory(); s++) {
+ if (mInventory != null && mInventory[s] != null) {
+ ItemStack slot = mInventory[s];
+ if (slot == null || (slot != null && GT_Utility.areStacksEqual(aInput, slot)
+ && slot.stackSize != slot.getItem()
+ .getItemStackLimit(slot))) {
+ if (slot == null) {
+ slot = aInput.copy();
+ } else {
+ slot.stackSize++;
+ }
+ this.setInventorySlotContents(s, slot);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public final void purgeNulls() {
+ ItemStack[] aTemp = ArrayUtils.removeNulls(this.mInventory);
+ for (int g = 0; g < this.getSizeInventory(); g++) {
+ if (aTemp.length < this.getSizeInventory()) {
+ if (g <= aTemp.length - 1) {
+ this.mInventory[g] = aTemp[g];
+ } else {
+ this.mInventory[g] = null;
+ }
+ } else {
+ this.mInventory[g] = aTemp[g];
+ }
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/BlockPos.java b/src/main/java/gtPlusPlus/api/objects/minecraft/BlockPos.java
new file mode 100644
index 0000000000..3853f61793
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/BlockPos.java
@@ -0,0 +1,245 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+import net.minecraft.block.Block;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.world.World;
+import net.minecraftforge.common.DimensionManager;
+
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gtPlusPlus.api.objects.data.AutoMap;
+
+public class BlockPos implements Serializable {
+
+ private static final long serialVersionUID = -7271947491316682006L;
+ public final int xPos;
+ public final int yPos;
+ public final int zPos;
+ public final int dim;
+ public final transient World world;
+
+ public static BlockPos generateBlockPos(String sUUID) {
+ String[] s2 = sUUID.split("@");
+ return new BlockPos(s2);
+ }
+
+ public BlockPos(String[] s) {
+ this(Integer.parseInt(s[1]), Integer.parseInt(s[2]), Integer.parseInt(s[3]), Integer.parseInt(s[0]));
+ }
+
+ public BlockPos(int x, int y, int z) {
+ this(x, y, z, 0);
+ }
+
+ public BlockPos(int x, int y, int z, int dim) {
+ this(x, y, z, DimensionManager.getWorld(dim));
+ }
+
+ public BlockPos(int x, int y, int z, World dim) {
+ this.xPos = x;
+ this.yPos = y;
+ this.zPos = z;
+
+ if (dim != null) {
+ this.dim = dim.provider.dimensionId;
+ this.world = dim;
+ } else {
+ this.dim = 0;
+ this.world = null;
+ }
+ }
+
+ public BlockPos(IGregTechTileEntity b) {
+ this(b.getXCoord(), b.getYCoord(), b.getZCoord(), b.getWorld());
+ }
+
+ public BlockPos(TileEntity b) {
+ this(b.xCoord, b.yCoord, b.zCoord, b.getWorldObj());
+ }
+
+ public String getLocationString() {
+ return "[X: " + this.xPos + "][Y: " + this.yPos + "][Z: " + this.zPos + "][Dim: " + this.dim + "]";
+ }
+
+ public String getUniqueIdentifier() {
+ String S = "" + this.dim + "@" + this.xPos + "@" + this.yPos + "@" + this.zPos;
+ return S;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash += (13 * this.xPos);
+ hash += (19 * this.yPos);
+ hash += (31 * this.zPos);
+ hash += (17 * this.dim);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) {
+ return false;
+ }
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof BlockPos otherPoint)) {
+ return false;
+ }
+ return this.xPos == otherPoint.xPos && this.yPos == otherPoint.yPos
+ && this.zPos == otherPoint.zPos
+ && this.dim == otherPoint.dim;
+ }
+
+ public int distanceFrom(BlockPos target) {
+ if (target.dim != this.dim) {
+ return Short.MIN_VALUE;
+ }
+ return distanceFrom(target.xPos, target.yPos, target.zPos);
+ }
+
+ /**
+ *
+ * @param x X coordinate of target.
+ * @param y Y coordinate of target.
+ * @param z Z coordinate of target.
+ * @return square of distance
+ */
+ public int distanceFrom(int x, int y, int z) {
+ int distanceX = this.xPos - x;
+ int distanceY = this.yPos - y;
+ int distanceZ = this.zPos - z;
+ return distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ;
+ }
+
+ public boolean isWithinRange(BlockPos target, int range) {
+ if (target.dim != this.dim) {
+ return false;
+ }
+ return isWithinRange(target.xPos, target.yPos, target.zPos, range);
+ }
+
+ public boolean isWithinRange(int x, int y, int z, int range) {
+ return distanceFrom(x, y, z) <= (range * range);
+ }
+
+ public BlockPos getUp() {
+ return new BlockPos(this.xPos, this.yPos + 1, this.zPos, this.dim);
+ }
+
+ public BlockPos getDown() {
+ return new BlockPos(this.xPos, this.yPos - 1, this.zPos, this.dim);
+ }
+
+ public BlockPos getXPos() {
+ return new BlockPos(this.xPos + 1, this.yPos, this.zPos, this.dim);
+ }
+
+ public BlockPos getXNeg() {
+ return new BlockPos(this.xPos - 1, this.yPos, this.zPos, this.dim);
+ }
+
+ public BlockPos getZPos() {
+ return new BlockPos(this.xPos, this.yPos, this.zPos + 1, this.dim);
+ }
+
+ public BlockPos getZNeg() {
+ return new BlockPos(this.xPos, this.yPos, this.zPos - 1, this.dim);
+ }
+
+ public AutoMap<BlockPos> getSurroundingBlocks() {
+ AutoMap<BlockPos> sides = new AutoMap<>();
+ sides.put(getUp());
+ sides.put(getDown());
+ sides.put(getXPos());
+ sides.put(getXNeg());
+ sides.put(getZPos());
+ sides.put(getZNeg());
+ return sides;
+ }
+
+ public Block getBlockAtPos() {
+ return getBlockAtPos(this);
+ }
+
+ public Block getBlockAtPos(BlockPos pos) {
+ return getBlockAtPos(world, pos);
+ }
+
+ public Block getBlockAtPos(World world, BlockPos pos) {
+ return world.getBlock(pos.xPos, pos.yPos, pos.zPos);
+ }
+
+ public int getMetaAtPos() {
+ return getMetaAtPos(this);
+ }
+
+ public int getMetaAtPos(BlockPos pos) {
+ return getMetaAtPos(world, pos);
+ }
+
+ public int getMetaAtPos(World world, BlockPos pos) {
+ return world.getBlockMetadata(pos.xPos, pos.yPos, pos.zPos);
+ }
+
+ public boolean hasSimilarNeighbour() {
+ return hasSimilarNeighbour(false);
+ }
+
+ /**
+ * @param strict - Does this check Meta Data?
+ * @return - Does this block have a neighbour that is the same?
+ */
+ public boolean hasSimilarNeighbour(boolean strict) {
+ for (BlockPos g : getSurroundingBlocks().values()) {
+ if (getBlockAtPos(g) == getBlockAtPos()) {
+ if (!strict) {
+ return true;
+ } else {
+ if (getMetaAtPos() == getMetaAtPos(g)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public AutoMap<BlockPos> getSimilarNeighbour() {
+ return getSimilarNeighbour(false);
+ }
+
+ /**
+ * @param strict - Does this check Meta Data?
+ * @return - Does this block have a neighbour that is the same?
+ */
+ public AutoMap<BlockPos> getSimilarNeighbour(boolean strict) {
+ AutoMap<BlockPos> sides = new AutoMap<>();
+ for (BlockPos g : getSurroundingBlocks().values()) {
+ if (getBlockAtPos(g) == getBlockAtPos()) {
+ if (!strict) {
+ sides.put(g);
+ } else {
+ if (getMetaAtPos() == getMetaAtPos(g)) {
+ sides.put(g);
+ }
+ }
+ }
+ }
+ return sides;
+ }
+
+ public Set<BlockPos> getValidNeighboursAndSelf() {
+ AutoMap<BlockPos> h = getSimilarNeighbour(true);
+ h.put(this);
+ Set<BlockPos> result = new HashSet<>();
+ for (BlockPos f : h.values()) {
+ result.add(f);
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/CubicObject.java b/src/main/java/gtPlusPlus/api/objects/minecraft/CubicObject.java
new file mode 100644
index 0000000000..5620b76895
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/CubicObject.java
@@ -0,0 +1,56 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gtPlusPlus.api.objects.data.AutoMap;
+
+public class CubicObject<T> {
+
+ public final T NORTH;
+ public final T SOUTH;
+
+ public final T WEST;
+ public final T EAST;
+
+ public final T UP;
+ public final T DOWN;
+
+ public CubicObject(AutoMap<T> aDataSet) {
+ this(aDataSet.get(0), aDataSet.get(1), aDataSet.get(2), aDataSet.get(3), aDataSet.get(4), aDataSet.get(5));
+ }
+
+ public CubicObject(T[] aDataSet) {
+ this(aDataSet[0], aDataSet[1], aDataSet[2], aDataSet[3], aDataSet[4], aDataSet[5]);
+ }
+
+ public CubicObject(T aDOWN, T aUP, T aNORTH, T aSOUTH, T aWEST, T aEAST) {
+ DOWN = aDOWN;
+ UP = aUP;
+ NORTH = aNORTH;
+ SOUTH = aSOUTH;
+ WEST = aWEST;
+ EAST = aEAST;
+ }
+
+ public T get(int ordinalSide) {
+ return get(ForgeDirection.getOrientation(ordinalSide));
+ }
+
+ public T get(ForgeDirection side) {
+ if (side == ForgeDirection.DOWN) {
+ return DOWN;
+ } else if (side == ForgeDirection.UP) {
+ return UP;
+ } else if (side == ForgeDirection.NORTH) {
+ return NORTH;
+ } else if (side == ForgeDirection.SOUTH) {
+ return SOUTH;
+ } else if (side == ForgeDirection.WEST) {
+ return WEST;
+ } else if (side == ForgeDirection.EAST) {
+ return EAST;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/FluidGT6.java b/src/main/java/gtPlusPlus/api/objects/minecraft/FluidGT6.java
new file mode 100644
index 0000000000..c5c903cd1f
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/FluidGT6.java
@@ -0,0 +1,33 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import static gregtech.api.enums.Mods.GTPlusPlus;
+
+import net.minecraftforge.fluids.Fluid;
+
+import gregtech.api.GregTech_API;
+
+public class FluidGT6 extends Fluid implements Runnable {
+
+ private final short[] mRGBa;
+ public final String mTextureName;
+
+ public FluidGT6(final String aName, final String aTextureName, final short[] aRGBa) {
+ super(aName);
+ this.mRGBa = aRGBa;
+ this.mTextureName = aTextureName;
+ if (GregTech_API.sGTBlockIconload != null) {
+ GregTech_API.sGTBlockIconload.add(this);
+ }
+ }
+
+ @Override
+ public int getColor() {
+ return (Math.max(0, Math.min(255, this.mRGBa[0])) << 16) | (Math.max(0, Math.min(255, this.mRGBa[1])) << 8)
+ | Math.max(0, Math.min(255, this.mRGBa[2]));
+ }
+
+ @Override
+ public void run() {
+ this.setIcons(GregTech_API.sBlockIcons.registerIcon(GTPlusPlus.ID + ":" + "fluids/fluid." + this.mTextureName));
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/ItemPackage.java b/src/main/java/gtPlusPlus/api/objects/minecraft/ItemPackage.java
new file mode 100644
index 0000000000..d68ef1a93f
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/ItemPackage.java
@@ -0,0 +1,57 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
+import gtPlusPlus.api.interfaces.RunnableWithInfo;
+import gtPlusPlus.core.handler.COMPAT_HANDLER;
+
+public abstract class ItemPackage implements RunnableWithInfo<String> {
+
+ public ItemPackage() {
+ this(false);
+ }
+
+ public ItemPackage(boolean hasExtraLateRun) {
+ // Register for late run
+ COMPAT_HANDLER.mObjectsToRunInPostInit.put(this);
+ if (hasExtraLateRun) {
+ COMPAT_HANDLER.mObjectsToRunInOnLoadComplete.put(this);
+ }
+ init();
+ }
+
+ @Override
+ public final void run() {
+ generateRecipes();
+ }
+
+ @Override
+ public final String getInfoData() {
+ return errorMessage();
+ }
+
+ public abstract String errorMessage();
+
+ public abstract boolean generateRecipes();
+
+ private void init() {
+ items();
+ blocks();
+ fluids();
+ }
+
+ public abstract void items();
+
+ public abstract void blocks();
+
+ public abstract void fluids();
+
+ /**
+ * Override this to handle GT Recipe map manipulation after they're Baked.
+ *
+ * @param event - the {@link FMLLoadCompleteEvent}.
+ * @return - Did we do anything?
+ */
+ public boolean onLoadComplete(FMLLoadCompleteEvent event) {
+ return false;
+ };
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/ItemStackData.java b/src/main/java/gtPlusPlus/api/objects/minecraft/ItemStackData.java
new file mode 100644
index 0000000000..f5e483b91c
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/ItemStackData.java
@@ -0,0 +1,34 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+
+public class ItemStackData {
+
+ protected final Item mItem;
+ protected final int mDamage;
+ protected final int mStackSize;
+ protected final NBTTagCompound mNBT;
+ protected final String mUniqueDataTag;
+
+ public ItemStackData(ItemStack aStack) {
+ mItem = aStack.getItem();
+ mDamage = aStack.getItemDamage();
+ mStackSize = aStack.stackSize;
+ mNBT = (aStack.getTagCompound() != null ? aStack.getTagCompound() : new NBTTagCompound());
+ mUniqueDataTag = "" + Item.getIdFromItem(mItem) + "" + mDamage + "" + mStackSize + "" + mNBT.getId();
+ }
+
+ public String getUniqueDataIdentifier() {
+ return this.mUniqueDataTag;
+ }
+
+ public ItemStack getStack() {
+ ItemStack aTemp = ItemUtils.simpleMetaStack(mItem, mDamage, mStackSize);
+ aTemp.setTagCompound(mNBT);
+ return aTemp;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/SafeTexture.java b/src/main/java/gtPlusPlus/api/objects/minecraft/SafeTexture.java
new file mode 100644
index 0000000000..58a7affa90
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/SafeTexture.java
@@ -0,0 +1,65 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import java.util.HashMap;
+
+import net.minecraft.util.IIcon;
+
+import cpw.mods.fml.relauncher.Side;
+import cpw.mods.fml.relauncher.SideOnly;
+import gregtech.api.GregTech_API;
+import gtPlusPlus.core.util.Utils;
+
+/**
+ * A Server Side safe object that can hold {@link IIcon}s.
+ *
+ * @author Alkalus
+ *
+ */
+public class SafeTexture implements Runnable {
+
+ @SideOnly(Side.CLIENT)
+ private static final HashMap<Integer, IIcon> mHashToIconCache = new HashMap<>();
+
+ @SideOnly(Side.CLIENT)
+ private static final HashMap<String, Integer> mPathToHashCash = new HashMap<>();
+
+ private static final HashMap<String, SafeTexture> mTextureObjectCache = new HashMap<>();
+
+ private final int mHash;
+
+ private final String mTextureName;
+
+ private static String getKey(String aTexPath) {
+ String aNameKey = Utils.sanitizeString(aTexPath);
+ aNameKey = aNameKey.replace('/', ' ');
+ aNameKey = aNameKey.toLowerCase();
+ return aNameKey;
+ }
+
+ public static SafeTexture register(String aTexturePath) {
+ String aNameKey = getKey(aTexturePath);
+ SafeTexture g = mTextureObjectCache.get(aNameKey);
+ if (g == null) {
+ g = new SafeTexture(aTexturePath);
+ mTextureObjectCache.put(aNameKey, g);
+ mPathToHashCash.put(aTexturePath, aTexturePath.hashCode());
+ }
+ return g;
+ }
+
+ private SafeTexture(String aTexturePath) {
+ mTextureName = aTexturePath;
+ mHash = getKey(aTexturePath).hashCode();
+ GregTech_API.sGTBlockIconload.add(this);
+ }
+
+ @SideOnly(Side.CLIENT)
+ public IIcon getIcon() {
+ return mHashToIconCache.get(mHash);
+ }
+
+ @Override
+ public void run() {
+ mHashToIconCache.put(getKey(mTextureName).hashCode(), GregTech_API.sBlockIcons.registerIcon(mTextureName));
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/ShapedRecipe.java b/src/main/java/gtPlusPlus/api/objects/minecraft/ShapedRecipe.java
new file mode 100644
index 0000000000..f799623dd6
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/ShapedRecipe.java
@@ -0,0 +1,251 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.oredict.ShapedOreRecipe;
+
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.api.objects.data.AutoMap;
+import gtPlusPlus.api.objects.data.Pair;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+
+public class ShapedRecipe {
+
+ private static final String CHARS = "abcdefghijklmnop";
+ public ShapedOreRecipe mRecipe;
+
+ ItemStack[] mBlackList = null;
+
+ public ShapedRecipe(Object aInput1, Object aInput2, Object aInput3, Object aInput4, Object aInput5, Object aInput6,
+ Object aInput7, Object aInput8, Object aInput9, ItemStack aOutput) {
+
+ this(new Object[] { aInput1, aInput2, aInput3, aInput4, aInput5, aInput6, aInput7, aInput8, aInput9 }, aOutput);
+ }
+
+ public ShapedRecipe(Object[] aInputs, ItemStack aOutput) {
+ String aGridWhole = "";
+ String aGrid[] = new String[3];
+ char[] aChar = new char[9];
+ String[] aLoggingInfo = new String[9];
+
+ if (mBlackList == null) {
+ mBlackList = new ItemStack[] {};
+ }
+
+ // Just to be safe
+ try {
+ int xSlot = 0;
+ int xNull = 0;
+ for (Object u : aInputs) {
+ String mInfo = "";
+ if (u instanceof String) {
+ mInfo = (String) u;
+ Logger.RECIPE("Input slot " + xSlot++ + " contains " + mInfo);
+ } else if (u instanceof ItemStack || u instanceof Item) {
+ if (u instanceof Item) {
+ u = ItemUtils.getSimpleStack((Item) u);
+ }
+ mInfo = ((ItemStack) u).getDisplayName();
+ Logger.RECIPE("Input slot " + xSlot++ + " contains " + mInfo);
+ } else if (u == null) {
+ xNull++;
+ }
+ }
+ Logger.RECIPE("Found " + xNull + " null inputs.");
+ // Check if the output is invalid
+ if (aOutput != null && xNull < 9) {
+
+ for (ItemStack q : mBlackList) {
+ if (q != null) {
+ if (q.isItemEqual(aOutput)) {
+ Logger.RECIPE("Found recipe Alkalus is Debugging.");
+ }
+ }
+ }
+
+ Object[] mVarags2 = null;
+ Logger.RECIPE("Generating Shaped Crafting Recipe for " + aOutput.getDisplayName());
+
+ if (aInputs.length < 9 || aInputs.length > 9) {
+ Logger.RECIPE(
+ "[Fix] Recipe for " + aOutput.getDisplayName()
+ + " has incorrect number of inputs. Size: "
+ + aInputs.length
+ + ".");
+ }
+
+ // Build a Pair for each slot
+ AutoMap<Pair<Character, Object>> aRecipePairs = new AutoMap<>();
+ int aCharSlot = 0;
+ int aMemSlot = 0;
+ int aInfoSlot = 0;
+ for (Object stack : aInputs) {
+ if (stack != null) {
+ String mInfo = "";
+ if (stack instanceof String) {
+ mInfo = (String) stack;
+ } else if (stack instanceof ItemStack || stack instanceof Item) {
+ if (stack instanceof Item) {
+ stack = ItemUtils.getSimpleStack((Item) stack);
+ }
+ mInfo = ((ItemStack) stack).getDisplayName();
+ }
+ aRecipePairs.put(new Pair<>(CHARS.charAt(aCharSlot), stack));
+ Logger.RECIPE(
+ "Storing '" + CHARS.charAt(aCharSlot)
+ + "' with an object of type "
+ + stack.getClass()
+ .getSimpleName()
+ + " and a value of "
+ + mInfo);
+ aChar[aMemSlot++] = CHARS.charAt(aCharSlot);
+ aCharSlot++;
+ aLoggingInfo[aInfoSlot++] = mInfo;
+ } else {
+ aRecipePairs.put(new Pair<>(' ', (ItemStack) null));
+ Logger.RECIPE("Storing ' ' with an object of type null");
+ aChar[aMemSlot++] = ' ';
+ aLoggingInfo[aInfoSlot++] = "Empty";
+ }
+ }
+
+ Logger.RECIPE(aRecipePairs.size() + " Char|Object pairs registered for recipe.");
+ // If we have enough valid slots, iterate them and build a String which represents the entire grid.
+ // If this String is the correct length, we will split it into thirds and build the grid String array.
+ if (aRecipePairs.size() == 9) {
+
+ for (Pair<Character, Object> h : aRecipePairs) {
+ if (h.getKey() != null) {
+ aGridWhole += String.valueOf(h.getKey());
+ Logger.RECIPE("Adding '" + String.valueOf(h.getKey()) + "' to aGridWhole.");
+ }
+ }
+
+ Logger.RECIPE("aGridWhole: " + aGridWhole + " | size: " + aGridWhole.length());
+
+ // Build crafting grid
+ if (aGridWhole.length() == 9) {
+ Logger.RECIPE("aGridWhole size == 9");
+ aGrid[0] = "" + aGridWhole.charAt(0) + aGridWhole.charAt(1) + aGridWhole.charAt(2);
+ aGrid[1] = "" + aGridWhole.charAt(3) + aGridWhole.charAt(4) + aGridWhole.charAt(5);
+ aGrid[2] = "" + aGridWhole.charAt(6) + aGridWhole.charAt(7) + aGridWhole.charAt(8);
+ } else {
+ Logger.RECIPE(
+ "[Fix] Grid length for recipe outputting " + aOutput.getDisplayName() + " is not 9.");
+ }
+
+ // Rebuild the Map without spaces
+ aRecipePairs.clear();
+ aCharSlot = 0;
+
+ // The amount of spaces in the Varags that the Shape strings takes.
+ // Currently they are inserted as a single array into index 0.
+ final int KEY_COUNTER = 1;
+
+ int counter = KEY_COUNTER;
+ for (Object stack : aInputs) {
+ if (stack != null) {
+ String mInfo = "";
+ if (stack instanceof String) {
+ mInfo = (String) stack;
+ } else if (stack instanceof ItemStack || stack instanceof Item) {
+ if (stack instanceof Item) {
+ stack = ItemUtils.getSimpleStack((Item) stack);
+ }
+ mInfo = ((ItemStack) stack).getDisplayName();
+ }
+ aRecipePairs.put(new Pair<>(CHARS.charAt(aCharSlot), stack));
+ Logger.RECIPE(
+ "Registering Pair of '" + CHARS.charAt(aCharSlot)
+ + "' and a "
+ + stack.getClass()
+ .getSimpleName()
+ + " object. Object has a value of "
+ + mInfo);
+ aCharSlot++;
+ counter++;
+ }
+ }
+
+ Logger.RECIPE(
+ "Counter started at " + KEY_COUNTER
+ + ", counter is now at "
+ + counter
+ + ". Trying to create Varag array with a size of "
+ + (KEY_COUNTER + (counter - KEY_COUNTER) * 2));
+ // Counter started at 3, counter is now at 4. Trying to create Varag array with a size of 2
+
+ // Register the shaped grid straight to the varags
+ mVarags2 = new Object[(KEY_COUNTER + (counter - KEY_COUNTER) * 2)];
+ /*
+ * mVarags2[0] = aGrid[0]; mVarags2[1] = aGrid[1]; mVarags2[2] = aGrid[2];
+ */
+ mVarags2[0] = aGrid;
+
+ // Add Each Char, then Item to the varags, sequentially.
+ int counter2 = KEY_COUNTER;
+ for (Pair<Character, Object> r : aRecipePairs) {
+ char c = r.getKey();
+ Object o = r.getValue();
+
+ if (o instanceof ItemStack || o instanceof Item) {
+ if (o instanceof Item) {
+ o = ItemUtils.getSimpleStack((Item) o);
+ }
+ o = ((ItemStack) o).copy();
+ }
+
+ mVarags2[counter2] = (char) c;
+ mVarags2[counter2 + 1] = o;
+ counter2 += 2;
+ }
+
+ Logger.RECIPE("Recipe Summary");
+ Logger.RECIPE("+ = + = + = +");
+ Logger.RECIPE("= " + aChar[0] + " = " + aChar[1] + " = " + aChar[2] + " =");
+ Logger.RECIPE("+ = + = + = +");
+ Logger.RECIPE("= " + aChar[3] + " = " + aChar[4] + " = " + aChar[5] + " =");
+ Logger.RECIPE("+ = + = + = +");
+ Logger.RECIPE("= " + aChar[6] + " = " + aChar[7] + " = " + aChar[8] + " =");
+ Logger.RECIPE("+ = + = + = +");
+ for (int r = 0; r < 9; r++) {
+ if (aChar[r] != ' ') {
+ Logger.RECIPE("" + aChar[r] + " : " + aLoggingInfo[r]);
+ }
+ }
+
+ } else {
+ Logger.RECIPE(
+ "[Fix] Recipe for " + aOutput.getDisplayName() + " contains a strange number of inputs.");
+ }
+
+ // Try set the recipe for this object.
+ ShapedOreRecipe testRecipe = null;
+ try {
+ testRecipe = new ShapedOreRecipe(aOutput, mVarags2);
+ } catch (Throwable t) {
+ Logger.RECIPE("[Fix][0] Error thrown when making a ShapedOreRecipe object.");
+ t.printStackTrace();
+ }
+ if (testRecipe == null) {
+ this.mRecipe = null;
+ Logger.RECIPE("[Fix] Failed to generate a shaped recipe.");
+ } else {
+ this.mRecipe = testRecipe;
+ Logger.RECIPE("Generated a shaped recipe successfully.");
+ }
+ }
+
+ // Output was not valid
+ else {
+ this.mRecipe = null;
+ Logger.RECIPE("[Fix] Failed to generate a shaped recipe. Output was not valid.");
+ }
+
+ } catch (Throwable t) {
+ this.mRecipe = null;
+ Logger.RECIPE("[Fix][1] Error thrown when making a ShapedOreRecipe object.");
+ t.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/recipe/ChemicalPlantFrontend.java b/src/main/java/gtPlusPlus/api/recipe/ChemicalPlantFrontend.java
new file mode 100644
index 0000000000..beede78173
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/recipe/ChemicalPlantFrontend.java
@@ -0,0 +1,68 @@
+package gtPlusPlus.api.recipe;
+
+import static net.minecraft.util.EnumChatFormatting.GRAY;
+
+import java.util.List;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import com.gtnewhorizons.modularui.api.math.Pos2d;
+
+import gregtech.api.recipe.BasicUIPropertiesBuilder;
+import gregtech.api.recipe.NEIRecipePropertiesBuilder;
+import gregtech.api.recipe.RecipeMapFrontend;
+import gregtech.api.util.MethodsReturnNonnullByDefault;
+import gregtech.common.gui.modularui.UIHelper;
+import gregtech.nei.GT_NEI_DefaultHandler;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+
+@ParametersAreNonnullByDefault
+@MethodsReturnNonnullByDefault
+public class ChemicalPlantFrontend extends RecipeMapFrontend {
+
+ public ChemicalPlantFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder,
+ NEIRecipePropertiesBuilder neiPropertiesBuilder) {
+ super(uiPropertiesBuilder, neiPropertiesBuilder);
+ }
+
+ @Override
+ public List<Pos2d> getItemInputPositions(int itemInputCount) {
+ return UIHelper.getGridPositions(itemInputCount, 7, 6, itemInputCount, 1);
+ }
+
+ @Override
+ public List<Pos2d> getItemOutputPositions(int itemOutputCount) {
+ return UIHelper.getGridPositions(itemOutputCount, 106, 6, 2);
+ }
+
+ @Override
+ public List<Pos2d> getFluidInputPositions(int fluidInputCount) {
+ return UIHelper.getGridPositions(fluidInputCount, 7, 41, fluidInputCount, 1);
+ }
+
+ @Override
+ public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) {
+ return UIHelper.getGridPositions(fluidOutputCount, 142, 6, 1, fluidOutputCount);
+ }
+
+ @Override
+ protected List<String> handleNEIItemInputTooltip(List<String> currentTip,
+ GT_NEI_DefaultHandler.FixedPositionedStack pStack) {
+ if (ItemUtils.isCatalyst(pStack.item)) {
+ currentTip.add(GRAY + "Does not always get consumed in the process");
+ currentTip.add(GRAY + "Higher tier pipe casings allow this item to last longer");
+ } else {
+ super.handleNEIItemInputTooltip(currentTip, pStack);
+ }
+ return currentTip;
+ }
+
+ @Override
+ protected void drawNEIOverlayForInput(GT_NEI_DefaultHandler.FixedPositionedStack stack) {
+ if (ItemUtils.isCatalyst(stack.item)) {
+ drawNEIOverlayText("NC*", stack);
+ } else {
+ super.drawNEIOverlayForInput(stack);
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/recipe/GTPPRecipeCategories.java b/src/main/java/gtPlusPlus/api/recipe/GTPPRecipeCategories.java
new file mode 100644
index 0000000000..310f6f540d
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/recipe/GTPPRecipeCategories.java
@@ -0,0 +1,17 @@
+package gtPlusPlus.api.recipe;
+
+import static gregtech.api.recipe.RecipeCategory.createIcon;
+
+import gregtech.api.enums.Mods;
+import gregtech.api.recipe.RecipeCategory;
+import gregtech.api.recipe.RecipeCategoryHolder;
+
+public class GTPPRecipeCategories {
+
+ @RecipeCategoryHolder
+ public static final RecipeCategory absNonAlloyRecipes = new RecipeCategory(
+ "gtpp.recipe.category.abs_non_alloy_recipes",
+ GTPPRecipeMaps.alloyBlastSmelterRecipes,
+ builder -> builder.setDisplayImage(
+ createIcon(Mods.GTPlusPlus.getResourcePath("textures", "gui", "picture", "abs_non_alloy_recipes.png"))));
+}
diff --git a/src/main/java/gtPlusPlus/api/recipe/GTPPRecipeMaps.java b/src/main/java/gtPlusPlus/api/recipe/GTPPRecipeMaps.java
new file mode 100644
index 0000000000..d2171d1bdd
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/recipe/GTPPRecipeMaps.java
@@ -0,0 +1,232 @@
+package gtPlusPlus.api.recipe;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import net.minecraft.util.StatCollector;
+
+import com.gtnewhorizons.modularui.common.widget.ProgressBar;
+
+import gregtech.api.gui.modularui.GT_UITextures;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMapBackend;
+import gregtech.api.recipe.RecipeMapBuilder;
+import gregtech.api.recipe.maps.FluidOnlyFrontend;
+import gregtech.api.recipe.maps.FuelBackend;
+import gregtech.api.recipe.maps.LargeNEIFrontend;
+import gregtech.api.util.GT_Utility;
+import gregtech.nei.formatter.FuelSpecialValueFormatter;
+import gregtech.nei.formatter.HeatingCoilSpecialValueFormatter;
+import gregtech.nei.formatter.SimpleSpecialValueFormatter;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.xmod.gregtech.api.gui.GTPP_UITextures;
+import gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.GregtechMetaTileEntityTreeFarm;
+
+public class GTPPRecipeMaps {
+
+ public static final RecipeMap<RecipeMapBackend> cokeOvenRecipes = RecipeMapBuilder.of("gtpp.recipe.cokeoven")
+ .maxIO(2, 9, 1, 1)
+ .minInputs(1, 0)
+ .progressBar(GT_UITextures.PROGRESSBAR_SIFT, ProgressBar.Direction.DOWN)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> multiblockMassFabricatorRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.matterfab2")
+ .maxIO(2, 0, 1, 1)
+ .build();
+ public static final RecipeMap<FuelBackend> rocketFuels = RecipeMapBuilder
+ .of("gtpp.recipe.rocketenginefuel", FuelBackend::new)
+ .maxIO(0, 0, 1, 0)
+ .neiSpecialInfoFormatter(
+ recipeInfo -> Collections.singletonList(
+ StatCollector.translateToLocalFormatted(
+ "GT5U.nei.fuel",
+ GT_Utility.formatNumbers(recipeInfo.recipe.mSpecialValue * 3000L))))
+ .build();
+ public static final RecipeMap<RecipeMapBackend> quantumForceTransformerRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.quantumforcesmelter")
+ .maxIO(6, 6, 6, 6)
+ .minInputs(1, 0)
+ .progressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE)
+ .neiSpecialInfoFormatter(new SimpleSpecialValueFormatter("GT5U.nei.tier"))
+ .frontend(LargeNEIFrontend::new)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> chemicalDehydratorRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.chemicaldehydrator")
+ .maxIO(2, 9, 1, 1)
+ .progressBar(GT_UITextures.PROGRESSBAR_SIFT, ProgressBar.Direction.DOWN)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> vacuumFurnaceRecipes = RecipeMapBuilder.of("gtpp.recipe.vacfurnace")
+ .maxIO(9, 9, 3, 3)
+ .minInputs(1, 0)
+ .neiSpecialInfoFormatter(HeatingCoilSpecialValueFormatter.INSTANCE)
+ .frontend(LargeNEIFrontend::new)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> alloyBlastSmelterRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.alloyblastsmelter")
+ .maxIO(9, 9, 3, 3)
+ .minInputs(1, 0)
+ .frontend(LargeNEIFrontend::new)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> liquidFluorineThoriumReactorRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.lftr")
+ .maxIO(0, 0, 6, 6)
+ .minInputs(0, 2)
+ .frontend(FluidOnlyFrontend::new)
+ .neiSpecialInfoFormatter(recipeInfo -> {
+ final long eut = recipeInfo.recipe.mSpecialValue;
+ final int duration = recipeInfo.recipe.mDuration;
+ return Arrays.asList(
+ StatCollector.translateToLocalFormatted("gtpp.nei.lftr.power", GT_Utility.formatNumbers(eut)),
+ StatCollector
+ .translateToLocalFormatted("gtpp.nei.lftr.dynamo", MathUtils.formatNumbers(duration * eut)),
+ StatCollector
+ .translateToLocalFormatted("gtpp.nei.lftr.total", MathUtils.formatNumbers(duration * eut * 4)));
+ })
+ .build();
+ public static final RecipeMap<RecipeMapBackend> nuclearSaltProcessingPlantRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.nuclearsaltprocessingplant")
+ .maxIO(1, 6, 2, 3)
+ .frontend(LargeNEIFrontend::new)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> millingRecipes = RecipeMapBuilder.of("gtpp.recipe.oremill")
+ .maxIO(3, 1, 0, 0)
+ .minInputs(1, 0)
+ .frontend(MillingFrontend::new)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> fissionFuelProcessingRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.fissionfuel")
+ .maxIO(0, 0, 6, 1)
+ .frontend(FluidOnlyFrontend::new)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> coldTrapRecipes = RecipeMapBuilder.of("gtpp.recipe.coldtrap")
+ .maxIO(2, 9, 1, 1)
+ .progressBar(GT_UITextures.PROGRESSBAR_SIFT, ProgressBar.Direction.DOWN)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> reactorProcessingUnitRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.reactorprocessingunit")
+ .maxIO(2, 9, 1, 1)
+ .progressBar(GT_UITextures.PROGRESSBAR_SIFT, ProgressBar.Direction.DOWN)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> simpleWasherRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.simplewasher")
+ .maxIO(1, 1, 1, 0)
+ .slotOverlays(
+ (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_CAULDRON : null)
+ .progressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> molecularTransformerRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.moleculartransformer")
+ .maxIO(1, 1, 0, 0)
+ .slotOverlays(
+ (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_MICROSCOPE
+ : null)
+ .neiHandlerInfo(
+ builder -> builder
+ .setDisplayStack(ItemUtils.getItemStackFromFQRN("AdvancedSolarPanel:BlockMolecularTransformer", 1)))
+ .build();
+ public static final RecipeMap<RecipeMapBackend> chemicalPlantRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.fluidchemicaleactor")
+ .maxIO(4, 6, 4, 3)
+ .slotOverlays((index, isFluid, isOutput, isSpecial) -> {
+ if (isFluid) {
+ if (isOutput) {
+ return GT_UITextures.OVERLAY_SLOT_VIAL_2;
+ }
+ return GT_UITextures.OVERLAY_SLOT_MOLECULAR_3;
+ }
+ if (isOutput) {
+ return GT_UITextures.OVERLAY_SLOT_VIAL_1;
+ }
+ return GT_UITextures.OVERLAY_SLOT_MOLECULAR_1;
+ })
+ .progressBar(GTPP_UITextures.PROGRESSBAR_FLUID_REACTOR, ProgressBar.Direction.CIRCULAR_CW)
+ .progressBarPos(82, 24)
+ .neiSpecialInfoFormatter(recipeInfo -> {
+ int tier = recipeInfo.recipe.mSpecialValue + 1;
+ String materialName = StatCollector.translateToLocal("gtpp.nei.chemplant.tier." + tier);
+ return Collections
+ .singletonList(StatCollector.translateToLocalFormatted("GT5U.nei.tier", tier + " - " + materialName));
+ })
+ .frontend(ChemicalPlantFrontend::new)
+ .build();
+ public static final RecipeMap<FuelBackend> rtgFuels = RecipeMapBuilder
+ .of("gtpp.recipe.RTGgenerators", FuelBackend::new)
+ .maxIO(1, 0, 0, 0)
+ .neiSpecialInfoFormatter(new SimpleSpecialValueFormatter("gtpp.nei.rtg.days", 365))
+ .build();
+ public static final RecipeMap<RecipeMapBackend> thermalBoilerRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.thermalgeneratorfuel")
+ .maxIO(0, 9, 2, 3)
+ .frontend(ThermalBoilerFrontend::new)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> solarTowerRecipes = RecipeMapBuilder.of("gtpp.recipe.solartower")
+ .maxIO(0, 0, 1, 1)
+ .neiSpecialInfoFormatter(
+ recipeInfo -> Arrays.asList(
+ StatCollector.translateToLocal("gtpp.nei.solar_tower.1"),
+ StatCollector.translateToLocal("gtpp.nei.solar_tower.2"),
+ StatCollector.translateToLocal("gtpp.nei.solar_tower.3")))
+ .frontend(FluidOnlyFrontend::new)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> cyclotronRecipes = RecipeMapBuilder.of("gtpp.recipe.cyclotron")
+ .maxIO(9, 9, 1, 1)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> fishPondRecipes = RecipeMapBuilder.of("gtpp.recipe.fishpond")
+ .maxIO(1, 1, 0, 0)
+ .slotOverlays(
+ (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_CAULDRON : null)
+ .progressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> spargeTowerFakeRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.spargetower")
+ .maxIO(0, 0, 9, 9)
+ .disableRegisterNEI()
+ .build();
+ public static final RecipeMap<RecipeMapBackend> advancedFreezerRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.cryogenicfreezer")
+ .maxIO(1, 1, 2, 1)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> centrifugeNonCellRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.multicentrifuge")
+ .maxIO(6, 6, 6, 6)
+ .progressBar(GT_UITextures.PROGRESSBAR_EXTRACT)
+ .frontend(LargeNEIFrontend::new)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> electrolyzerNonCellRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.multielectro")
+ .maxIO(6, 6, 6, 6)
+ .progressBar(GT_UITextures.PROGRESSBAR_EXTRACT)
+ .frontend(LargeNEIFrontend::new)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> mixerNonCellRecipes = RecipeMapBuilder.of("gtpp.recipe.multimixer")
+ .maxIO(9, 9, 6, 6)
+ .progressBar(GT_UITextures.PROGRESSBAR_MIXER, ProgressBar.Direction.CIRCULAR_CW)
+ .frontend(LargeNEIFrontend::new)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> chemicalDehydratorNonCellRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.multidehydrator")
+ .maxIO(6, 9, 3, 3)
+ .frontend(LargeNEIFrontend::new)
+ .build();
+ public static final RecipeMap<FuelBackend> semiFluidFuels = RecipeMapBuilder
+ .of("gtpp.recipe.semifluidgeneratorfuels", FuelBackend::new)
+ .maxIO(0, 0, 1, 0)
+ .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> flotationCellRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.flotationcell")
+ .maxIO(6, 0, 1, 1)
+ .build();
+ public static final RecipeMap<RecipeMapBackend> treeGrowthSimulatorFakeRecipes = RecipeMapBuilder
+ .of("gtpp.recipe.treefarm")
+ .maxIO(
+ GregtechMetaTileEntityTreeFarm.Mode.values().length,
+ GregtechMetaTileEntityTreeFarm.Mode.values().length,
+ 0,
+ 0)
+ .minInputs(1, 0)
+ .useSpecialSlot()
+ .frontend(TGSFrontend::new)
+ .build();
+}
diff --git a/src/main/java/gtPlusPlus/api/recipe/MillingFrontend.java b/src/main/java/gtPlusPlus/api/recipe/MillingFrontend.java
new file mode 100644
index 0000000000..26e2ab2ec9
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/recipe/MillingFrontend.java
@@ -0,0 +1,46 @@
+package gtPlusPlus.api.recipe;
+
+import static net.minecraft.util.EnumChatFormatting.GRAY;
+
+import java.util.List;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import net.minecraft.util.StatCollector;
+
+import gregtech.api.recipe.BasicUIPropertiesBuilder;
+import gregtech.api.recipe.NEIRecipePropertiesBuilder;
+import gregtech.api.recipe.RecipeMapFrontend;
+import gregtech.api.util.MethodsReturnNonnullByDefault;
+import gregtech.nei.GT_NEI_DefaultHandler;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+
+@ParametersAreNonnullByDefault
+@MethodsReturnNonnullByDefault
+public class MillingFrontend extends RecipeMapFrontend {
+
+ public MillingFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder,
+ NEIRecipePropertiesBuilder neiPropertiesBuilder) {
+ super(uiPropertiesBuilder, neiPropertiesBuilder);
+ }
+
+ @Override
+ protected List<String> handleNEIItemInputTooltip(List<String> currentTip,
+ GT_NEI_DefaultHandler.FixedPositionedStack pStack) {
+ if (ItemUtils.isMillingBall(pStack.item)) {
+ currentTip.add(GRAY + StatCollector.translateToLocal("gtpp.nei.milling.not_consumed"));
+ } else {
+ super.handleNEIItemInputTooltip(currentTip, pStack);
+ }
+ return currentTip;
+ }
+
+ @Override
+ protected void drawNEIOverlayForInput(GT_NEI_DefaultHandler.FixedPositionedStack stack) {
+ if (ItemUtils.isMillingBall(stack.item)) {
+ drawNEIOverlayText("NC*", stack);
+ } else {
+ super.drawNEIOverlayForInput(stack);
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/recipe/TGSFrontend.java b/src/main/java/gtPlusPlus/api/recipe/TGSFrontend.java
new file mode 100644
index 0000000000..e57ebaf5f9
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/recipe/TGSFrontend.java
@@ -0,0 +1,147 @@
+package gtPlusPlus.api.recipe;
+
+import java.awt.Rectangle;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+
+import com.gtnewhorizons.modularui.api.math.Pos2d;
+
+import gregtech.api.recipe.BasicUIPropertiesBuilder;
+import gregtech.api.recipe.NEIRecipePropertiesBuilder;
+import gregtech.api.recipe.RecipeMapFrontend;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.MethodsReturnNonnullByDefault;
+import gregtech.common.gui.modularui.UIHelper;
+import gregtech.nei.GT_NEI_DefaultHandler;
+import gregtech.nei.RecipeDisplayInfo;
+import gregtech.nei.formatter.INEISpecialInfoFormatter;
+import gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.GregtechMetaTileEntityTreeFarm;
+import gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.GregtechMetaTileEntityTreeFarm.Mode;
+
+@ParametersAreNonnullByDefault
+@MethodsReturnNonnullByDefault
+public class TGSFrontend extends RecipeMapFrontend {
+
+ private static final int SLOT_SIZE = 18;
+ private static final int CENTER_X = 90;
+ private static final int SPECIAL_X = CENTER_X - SLOT_SIZE / 2;
+ private static final int SPECIAL_Y = 9;
+ private static final int INPUTS_X = CENTER_X - SLOT_SIZE * 3;
+ private static final int INPUTS_Y = SPECIAL_Y + SLOT_SIZE + SLOT_SIZE / 2;
+ private static final int OUTPUTS_X = CENTER_X + SLOT_SIZE;
+ private static final int OUTPUTS_Y = INPUTS_Y;
+
+ public TGSFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder, NEIRecipePropertiesBuilder neiPropertiesBuilder) {
+ super(
+ uiPropertiesBuilder
+ .addNEITransferRect(
+ new Rectangle(INPUTS_X + SLOT_SIZE * 2, INPUTS_Y + SLOT_SIZE / 2, SLOT_SIZE * 2, SLOT_SIZE))
+ .progressBarPos(new Pos2d(CENTER_X - 10, INPUTS_Y + SLOT_SIZE / 2)),
+ neiPropertiesBuilder.neiSpecialInfoFormatter(new TGSSpecialValueFormatter()));
+ }
+
+ @Override
+ protected void drawEnergyInfo(RecipeDisplayInfo recipeInfo) {
+ // Do not.
+ }
+
+ @Override
+ public Pos2d getSpecialItemPosition() {
+ return new Pos2d(SPECIAL_X, SPECIAL_Y);
+ }
+
+ @Override
+ public List<Pos2d> getItemInputPositions(int itemInputCount) {
+ return UIHelper.getGridPositions(Mode.values().length, INPUTS_X, INPUTS_Y, 2);
+ }
+
+ @Override
+ public List<Pos2d> getItemOutputPositions(int itemOutputCount) {
+ return UIHelper.getGridPositions(Mode.values().length, OUTPUTS_X, OUTPUTS_Y, 2);
+ }
+
+ private static final String[] tooltipInputs = { StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.saw"),
+ StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.cutter"),
+ StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.shears"),
+ StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.knife") };
+
+ private static final String[] tooltipOutputs = { StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.needsSaw"),
+ StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.needsCutter"),
+ StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.needsShears"),
+ StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.needsKnife") };
+ private static final String tooltipSapling = StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.sapling");
+ private static final String tooltipMultiplier = StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.multiplier");
+
+ @Override
+ public List<String> handleNEIItemTooltip(ItemStack stack, List<String> currentTip,
+ GT_NEI_DefaultHandler.CachedDefaultRecipe neiCachedRecipe) {
+
+ /*
+ * This gets a little complicated, because we want to assign tooltips to inputs/outputs based on which mode
+ * (saw, shears, etc.) they correspond to. But CachedDefaultRecipe does not retain this information for us. This
+ * is because some recipes don't output any items for some modes. For example, if a recipe only yields logs and
+ * leaves, then the outputs of GT_Recipe will be {log, null, leaves}. However, in CachedDefaultRecipe this gets
+ * condensed to just {log, leaves}, with null values omitted. So to figure out which item came from which mode,
+ * we need to step through both of these arrays simultaneously and match non-null inputs/outputs in GT_Recipe to
+ * inputs/outputs in CachedDefaultRecipe.
+ */
+
+ // The last input in neiCachedRecipe is always the special slot, this is the input sapling.
+ if (stack == neiCachedRecipe.mInputs.get(neiCachedRecipe.mInputs.size() - 1).item) {
+ currentTip.add(EnumChatFormatting.YELLOW + tooltipSapling);
+ super.handleNEIItemTooltip(stack, currentTip, neiCachedRecipe);
+ return currentTip;
+ }
+
+ GT_Recipe.GT_Recipe_WithAlt recipe = (GT_Recipe.GT_Recipe_WithAlt) neiCachedRecipe.mRecipe;
+
+ // Inputs
+ int slot = 0;
+ for (int mode = 0; mode < Mode.values().length; ++mode) {
+ if (mode < recipe.mOreDictAlt.length && recipe.mOreDictAlt[mode] != null) {
+ // There is a valid input in this mode.
+ if (slot < neiCachedRecipe.mInputs.size() && stack == neiCachedRecipe.mInputs.get(slot).item) {
+ int toolMultiplier = GregtechMetaTileEntityTreeFarm.getToolMultiplier(stack, Mode.values()[mode]);
+ currentTip.add(EnumChatFormatting.YELLOW + tooltipInputs[mode]);
+ if (toolMultiplier > 0) {
+ currentTip.add(EnumChatFormatting.YELLOW + tooltipMultiplier + " " + toolMultiplier + "x");
+ }
+ return currentTip;
+ }
+ ++slot;
+ }
+ }
+
+ // Outputs
+ slot = 0;
+ for (int mode = 0; mode < Mode.values().length; ++mode) {
+ if (mode < recipe.mOutputs.length && recipe.mOutputs[mode] != null) {
+ // There is a valid output in this mode.
+ if (slot < neiCachedRecipe.mOutputs.size() && stack == neiCachedRecipe.mOutputs.get(slot).item) {
+ currentTip.add(EnumChatFormatting.YELLOW + tooltipOutputs[mode]);
+ return currentTip;
+ }
+ ++slot;
+ }
+ }
+
+ return currentTip;
+ }
+
+ private static class TGSSpecialValueFormatter implements INEISpecialInfoFormatter {
+
+ @Override
+ public List<String> format(RecipeDisplayInfo recipeInfo) {
+ return Arrays.asList(
+ StatCollector.translateToLocal("gtpp.nei.tgs.info-1"),
+ StatCollector.translateToLocal("gtpp.nei.tgs.info-2"),
+ StatCollector.translateToLocal("gtpp.nei.tgs.info-3"));
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/recipe/ThermalBoilerFrontend.java b/src/main/java/gtPlusPlus/api/recipe/ThermalBoilerFrontend.java
new file mode 100644
index 0000000000..93974b9f9a
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/recipe/ThermalBoilerFrontend.java
@@ -0,0 +1,57 @@
+package gtPlusPlus.api.recipe;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import com.gtnewhorizons.modularui.api.math.Pos2d;
+
+import gregtech.api.recipe.BasicUIPropertiesBuilder;
+import gregtech.api.recipe.NEIRecipePropertiesBuilder;
+import gregtech.api.recipe.maps.LargeNEIFrontend;
+import gregtech.api.util.MethodsReturnNonnullByDefault;
+import gregtech.common.gui.modularui.UIHelper;
+import gregtech.nei.RecipeDisplayInfo;
+import gregtech.nei.formatter.INEISpecialInfoFormatter;
+
+@ParametersAreNonnullByDefault
+@MethodsReturnNonnullByDefault
+public class ThermalBoilerFrontend extends LargeNEIFrontend {
+
+ private static final int tileSize = 18;
+ private static final int xOrigin = 16;
+ private static final int yOrigin = 8 + tileSize; // Aligned with second row of output items.
+ private static final int maxInputs = 3;
+
+ public ThermalBoilerFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder,
+ NEIRecipePropertiesBuilder neiPropertiesBuilder) {
+ super(
+ uiPropertiesBuilder,
+ neiPropertiesBuilder.neiSpecialInfoFormatter(new ThermalBoilerSpecialValueFormatter()));
+ }
+
+ @Override
+ public List<Pos2d> getFluidInputPositions(int fluidInputCount) {
+ return UIHelper
+ .getGridPositions(fluidInputCount, xOrigin + tileSize * (maxInputs - fluidInputCount), yOrigin, maxInputs);
+ }
+
+ private static class ThermalBoilerSpecialValueFormatter implements INEISpecialInfoFormatter {
+
+ @Override
+ public List<String> format(RecipeDisplayInfo recipeInfo) {
+ // TODO: Translation.
+ List<String> result = new ArrayList<>();
+ result.add("Steam output shown");
+ result.add("at maximum efficiency.");
+
+ if (recipeInfo.recipe.mSpecialValue == -1) {
+ result.add("Without a Lava Filter,");
+ result.add("only Obsidian is produced.");
+ }
+
+ return result;
+ }
+ }
+}