aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/kubatech/api/eig
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/kubatech/api/eig')
-rw-r--r--src/main/java/kubatech/api/eig/EIGBucket.java247
-rw-r--r--src/main/java/kubatech/api/eig/EIGDropTable.java224
-rw-r--r--src/main/java/kubatech/api/eig/EIGMode.java154
-rw-r--r--src/main/java/kubatech/api/eig/IEIGBucketFactory.java15
4 files changed, 640 insertions, 0 deletions
diff --git a/src/main/java/kubatech/api/eig/EIGBucket.java b/src/main/java/kubatech/api/eig/EIGBucket.java
new file mode 100644
index 0000000000..6a3dbdb642
--- /dev/null
+++ b/src/main/java/kubatech/api/eig/EIGBucket.java
@@ -0,0 +1,247 @@
+package kubatech.api.eig;
+
+import static kubatech.api.utils.ItemUtils.readItemStackFromNBT;
+import static kubatech.api.utils.ItemUtils.writeItemStackToNBT;
+
+import java.util.LinkedList;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.EnumChatFormatting;
+
+import gregtech.api.util.GT_Utility;
+import kubatech.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeIndustrialGreenhouse;
+
+public abstract class EIGBucket {
+
+ protected ItemStack seed;
+ protected int seedCount;
+ protected ItemStack[] supportItems;
+
+ public EIGBucket(ItemStack seed, int seedCount, ItemStack[] supportItem) {
+ this.seed = seed.copy();
+ this.seed.stackSize = 1;
+ this.seedCount = seedCount;
+ this.supportItems = supportItem;
+ }
+
+ public EIGBucket(NBTTagCompound nbt) {
+ this.seed = readItemStackFromNBT(nbt.getCompoundTag("seed"));
+ this.seedCount = nbt.getInteger("count");
+
+ // parse support items
+ if (nbt.hasKey("supportItems", 9)) {
+ NBTTagList supportItemsNBTList = nbt.getTagList("supportItems", 10);
+ if (supportItemsNBTList.tagCount() > 0) {
+ this.supportItems = new ItemStack[supportItemsNBTList.tagCount()];
+ for (int i = 0; i < supportItemsNBTList.tagCount(); i++) {
+ this.supportItems[i] = readItemStackFromNBT(supportItemsNBTList.getCompoundTagAt(i));
+ }
+ } else {
+ supportItems = null;
+ }
+ } else {
+ supportItems = null;
+ }
+ }
+
+ /**
+ * Creates a persistent save of the bucket's current data.
+ *
+ * @return The nbt data for this bucket.
+ */
+ public NBTTagCompound save() {
+ NBTTagCompound nbt = new NBTTagCompound();
+ nbt.setString("type", this.getNBTIdentifier());
+ nbt.setTag("seed", writeItemStackToNBT(this.seed));
+ nbt.setInteger("count", this.seedCount);
+ if (this.supportItems != null && this.supportItems.length > 0) {
+ NBTTagList supportItemNBT = new NBTTagList();
+ for (ItemStack supportItem : this.supportItems) {
+ supportItemNBT.appendTag(writeItemStackToNBT(supportItem));
+ }
+ nbt.setTag("supportItems", supportItemNBT);
+ }
+ return nbt;
+ }
+
+ /**
+ * Gets an item stack representing the seeds in this bucket
+ *
+ * @return an item stack representing the seeds in this bucket.
+ */
+ public ItemStack getSeedStack() {
+ ItemStack copied = this.seed.copy();
+ copied.stackSize = this.seedCount;
+ return copied;
+ }
+
+ /**
+ * Gets the number of seeds in this bucket
+ *
+ * @return gets the number of seeds in this bucket.
+ */
+ public int getSeedCount() {
+ return this.seedCount;
+ }
+
+ /**
+ * Gets the display name of the seed in this bucket
+ *
+ * @return The display name of the seed.
+ */
+ public String getDisplayName() {
+ return this.seed.getDisplayName();
+ }
+
+ public String getInfoData() {
+ StringBuilder sb = new StringBuilder();
+ // display invalid buckets, we don't want people to think they lost their seeds or something.
+ sb.append(this.isValid() ? EnumChatFormatting.GREEN : EnumChatFormatting.RED);
+ sb.append("x");
+ sb.append(this.getSeedCount());
+ sb.append(" ");
+ sb.append(this.getDisplayName());
+ this.getAdditionalInfoData(sb);
+ sb.append(EnumChatFormatting.RESET);
+ return sb.toString();
+ }
+
+ protected void getAdditionalInfoData(StringBuilder sb) {}
+
+ /**
+ * Attempts to add seeds to tbe bucket if the input is compatible
+ *
+ * @param input A stack of an item that may be able to be added to our current bucket.
+ * @param maxConsume The maximum amount of seeds to add to this bucket.
+ * @param simulate True if you want to see if you can add more seeds (useful for support item checks)
+ * @return number of seeds consumed, 0 for wrong item, -1 if it missed the support items, -2 if you tried to consume
+ * 0 or less items;
+ */
+ public int tryAddSeed(GT_MetaTileEntity_ExtremeIndustrialGreenhouse greenhouse, ItemStack input, int maxConsume,
+ boolean simulate) {
+ // Abort is input if empty
+ if (input == null || input.stackSize <= 0) return -2;
+ // Cap max to input count
+ maxConsume = Math.min(maxConsume, input.stackSize);
+ // Abort if item isn't an identical seed.
+ if (!GT_Utility.areStacksEqual(this.seed, input, false)) return 0;
+
+ // no support items, consume and exit early.
+ if (this.supportItems == null || this.supportItems.length <= 0) {
+ if (!simulate) {
+ input.stackSize -= maxConsume;
+ this.seedCount += maxConsume;
+ }
+ return maxConsume;
+ }
+
+ // Check if the item is found
+ LinkedList<ItemStack> toConsumeFrom = new LinkedList<>();
+ supportLoop: for (ItemStack supportItem : this.supportItems) {
+ for (ItemStack otherInput : greenhouse.getStoredInputs()) {
+ // filter usable inputs
+ if (otherInput == null || otherInput.stackSize <= 0) continue;
+ if (!GT_Utility.areStacksEqual(supportItem, otherInput, false)) continue;
+ // update max consume again
+ maxConsume = Math.min(maxConsume, otherInput.stackSize);
+ toConsumeFrom.addLast(otherInput);
+ continue supportLoop;
+ }
+ // no support found, no seeds added
+ return -1;
+ }
+
+ // consume items
+ if (!simulate) {
+ input.stackSize -= maxConsume;
+ for (ItemStack stack : toConsumeFrom) {
+ stack.stackSize -= maxConsume;
+ }
+ this.seedCount += maxConsume;
+ }
+ return maxConsume;
+ }
+
+ /**
+ * Attempts to remove a seed from the bucket
+ *
+ * @param toRemove The maximum amount of items to remove.
+ * @return The items that were removed from the bucket. Null if the bucket is empty.
+ */
+ public ItemStack[] tryRemoveSeed(int toRemove, boolean simulate) {
+ // validate inputs
+ toRemove = Math.min(this.seedCount, toRemove);
+ if (toRemove <= 0) return null;
+
+ // consume and return output
+ ItemStack[] ret = new ItemStack[1 + (this.supportItems == null ? 0 : this.supportItems.length)];
+ ret[0] = this.seed.copy();
+ ret[0].stackSize = toRemove;
+ if (this.supportItems != null) {
+ for (int i = 0; i < this.supportItems.length; i++) {
+ ret[i + 1] = this.supportItems[i].copy();
+ ret[i + 1].stackSize = toRemove;
+ }
+ }
+ if (!simulate) {
+ this.seedCount -= toRemove;
+ }
+ return ret;
+ }
+
+ /**
+ * Sets the seed count to 0 and returns item stacks representing every item in this bucket.
+ *
+ * @return The contents of the bucket
+ */
+ public ItemStack[] emptyBucket() {
+ if (this.seedCount <= 0) return null;
+ ItemStack[] ret = new ItemStack[1 + (this.supportItems == null ? 0 : this.supportItems.length)];
+ ret[0] = this.seed.copy();
+ ret[0].stackSize = this.seedCount;
+ if (this.supportItems != null) {
+ for (int i = 0; i < this.supportItems.length; i++) {
+ ret[i + 1] = this.supportItems[i].copy();
+ ret[i + 1].stackSize = this.seedCount;
+ }
+ }
+ this.seedCount = 0;
+ return ret;
+ }
+
+ /**
+ * Returns true if the bucket can output items.
+ *
+ * @return true if the bucket is valid.
+ */
+ public boolean isValid() {
+ return this.seed != null && this.seedCount > 0;
+ }
+
+ /**
+ * Gets the identifier used to identify this class during reconstruction
+ *
+ * @return the identifier for this bucket type.
+ */
+ protected abstract String getNBTIdentifier();
+
+ /**
+ * Adds item drops to the item tracker.
+ *
+ * @param multiplier A multiplier to apply to the output.
+ * @param tracker The item drop tracker
+ */
+ public abstract void addProgress(double multiplier, EIGDropTable tracker);
+
+ /**
+ * Attempts to revalidate a seed bucket. If it returns false, attempt to seed and support items and delete the
+ * bucket.
+ *
+ * @param greenhouse The greenhouse that contains the bucket.
+ * @return True if the bucket was successfully validated. {@link EIGBucket#isValid()} should also return true.
+ */
+ public abstract boolean revalidate(GT_MetaTileEntity_ExtremeIndustrialGreenhouse greenhouse);
+
+}
diff --git a/src/main/java/kubatech/api/eig/EIGDropTable.java b/src/main/java/kubatech/api/eig/EIGDropTable.java
new file mode 100644
index 0000000000..bb5bbe6456
--- /dev/null
+++ b/src/main/java/kubatech/api/eig/EIGDropTable.java
@@ -0,0 +1,224 @@
+package kubatech.api.eig;
+
+import static kubatech.api.utils.ItemUtils.readItemStackFromNBT;
+import static kubatech.api.utils.ItemUtils.writeItemStackToNBT;
+
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+
+import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
+
+public class EIGDropTable {
+
+ private static final String NBT_DROP_TABLE_ITEM_KEY = "item";
+ private static final String NBT_DROP_TABLE_COUNT_KEY = "count";
+
+ private final ItemStackMap<Double> dropTable;
+
+ /**
+ * Initialises a new empty drop table.
+ */
+ public EIGDropTable() {
+ this.dropTable = new ItemStackMap<>(true);
+ }
+
+ /**
+ * Loads a serialised drop table from nbt.
+ *
+ * @param nbt The nbt tag that contains the key for a drop table
+ * @param key The name of the key name for the drop table.
+ */
+ public EIGDropTable(NBTTagCompound nbt, String key) {
+ // should create an empty table if no drops are found.
+ this(nbt.getTagList(key, 10));
+ }
+
+ /**
+ * Loads a serialised drop table from nbt.
+ *
+ * @param nbt The nbt tag that contains the key for a drop table
+ */
+ public EIGDropTable(NBTTagList nbt) {
+ this();
+ for (int i = 0; i < nbt.tagCount(); i++) {
+ NBTTagCompound drop = nbt.getCompoundTagAt(i);
+ dropTable.merge(
+ readItemStackFromNBT(drop.getCompoundTag(NBT_DROP_TABLE_ITEM_KEY)),
+ drop.getDouble(NBT_DROP_TABLE_COUNT_KEY),
+ Double::sum);
+ }
+ }
+
+ /**
+ * Serialises the drop table to nbt
+ *
+ * @return The serialised drop table.
+ */
+ public NBTTagList save() {
+ NBTTagList nbt = new NBTTagList();
+ for (Map.Entry<ItemStack, Double> entry : this.dropTable.entrySet()) {
+ NBTTagCompound entryNBT = new NBTTagCompound();
+ entryNBT.setTag(NBT_DROP_TABLE_ITEM_KEY, writeItemStackToNBT(entry.getKey()));
+ entryNBT.setDouble(NBT_DROP_TABLE_COUNT_KEY, entry.getValue());
+ nbt.appendTag(entryNBT);
+ }
+ return nbt;
+ }
+
+ /**
+ * Adds a drop to the drop table
+ *
+ * @param itemStack The item to add to the table.
+ * @param amount The amount to add to the table.
+ */
+ public void addDrop(ItemStack itemStack, double amount) {
+ ItemStack key = itemStack.copy();
+ key.stackSize = 1;
+ this.dropTable.merge(key, amount, Double::sum);
+ }
+
+ /**
+ * Adds the values from this drop table to another, but multiplies the amount by a random amount bound by variance.
+ *
+ * @param target The drop table that you want to add the value to.
+ * @param variance How much to vary the amounts of this drop table to, 0 < x < 1 plz
+ * @param rand The random source for the variance.
+ */
+ public void addTo(EIGDropTable target, double variance, Random rand) {
+ this.addTo(target, 1.0, variance, rand);
+ }
+
+ /**
+ * Adds the values from this drop table to another, but multiplies the amount by a multiplier and a random amount
+ * bound by variance.
+ *
+ * @param target The drop table that you want to add the value to.
+ * @param multiplier A multiplier to apply to all amounts from this drop table.
+ * @param variance How much to vary the amounts of this drop table to, 0 < x < 1 plz.
+ * @param rand The random source for the variance.
+ */
+ public void addTo(EIGDropTable target, double multiplier, double variance, Random rand) {
+ this.addTo(target, variance * (rand.nextDouble() - 0.5) * multiplier);
+ }
+
+ /**
+ * Adds the values from this drop table to another.
+ *
+ * @param target The drop table that you want to add the value to.
+ */
+ public void addTo(EIGDropTable target) {
+ this.addTo(target, 1.0);
+ }
+
+ /**
+ * Adds the values from this drop table to another but multiplies the values by a multiplier.
+ *
+ * @param target The drop table that you want to add the value to.
+ * @param multiplier A multiplier to apply to all amounts from this drop table.
+ */
+ public void addTo(EIGDropTable target, double multiplier) {
+ for (Map.Entry<ItemStack, Double> entry : this.dropTable.entrySet()) {
+ target.dropTable.merge(entry.getKey(), entry.getValue() * multiplier, Double::sum);
+ }
+ }
+
+ /**
+ * Checks if the drop table is empty;
+ *
+ * @return true if empty.
+ */
+ public boolean isEmpty() {
+ return this.dropTable.isEmpty();
+ }
+
+ /**
+ * Returns the entry set for this drop table.
+ *
+ * @return ItemStack -> amount
+ */
+ public Set<Map.Entry<ItemStack, Double>> entrySet() {
+ return this.dropTable.entrySet();
+ }
+
+ /**
+ * Gets the amount for a specific item.
+ *
+ * @param item The item to look for.
+ * @return 0 if nothing is found else a positive value.
+ */
+ public double getItemAmount(ItemStack item) {
+ if (this.dropTable.containsKey(item)) {
+ return this.dropTable.get(item);
+ }
+ return 0;
+ }
+
+ /**
+ * Sets the amount for a specific item.
+ *
+ * @param item The item to look for.
+ */
+ public void setItemAmount(ItemStack item, double value) {
+ this.dropTable.put(item, value);
+ }
+
+ /**
+ * Removes an item from the drop table
+ *
+ * @param item The item to remove from the drop table.
+ */
+ public void removeItem(ItemStack item) {
+ this.dropTable.remove(item);
+ }
+
+ /**
+ * Creates a new drop table that is the intersection of this drop table and another.
+ *
+ *
+ * @param with The drop table to intersect with.
+ * @return The result of the intersection.
+ */
+ public EIGDropTable intersect(EIGDropTable with) {
+ EIGDropTable ret = new EIGDropTable();
+ for (ItemStack key : with.dropTable.keySet()) {
+ if (this.dropTable.containsKey(key)) {
+ ret.addDrop(key, this.dropTable.get(key));
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Consumes drops with drop counts above 1 and returns a list of the consumed item stacks.
+ *
+ * @return The list of consumed items;
+ */
+ public ItemStack[] getDrops() {
+ // doesn't need to filter for less than 0 so that the EIG displays the progress of incomplete items.
+ return this.dropTable.entrySet()
+ .parallelStream()
+ .map(EIGDropTable::computeDrops)
+ .toArray(ItemStack[]::new);
+ }
+
+ /**
+ * Consumes the items in the entry and returns the consumed item without removing partial items.
+ *
+ * @param entry The entry to consume from
+ * @return The item tha twas removed.
+ */
+ private static ItemStack computeDrops(Map.Entry<ItemStack, Double> entry) {
+ ItemStack copied = entry.getKey()
+ .copy();
+ copied.stackSize = (int) Math.floor(entry.getValue());
+ if (entry.getValue() >= 1.0d) {
+ entry.setValue(entry.getValue() % 1);
+ }
+ return copied;
+ }
+}
diff --git a/src/main/java/kubatech/api/eig/EIGMode.java b/src/main/java/kubatech/api/eig/EIGMode.java
new file mode 100644
index 0000000000..68ad633773
--- /dev/null
+++ b/src/main/java/kubatech/api/eig/EIGMode.java
@@ -0,0 +1,154 @@
+package kubatech.api.eig;
+
+import static kubatech.kubatech.error;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import kubatech.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeIndustrialGreenhouse;
+
+public abstract class EIGMode {
+
+ public abstract int getUIIndex();
+
+ public abstract String getName();
+
+ public abstract int getMinVoltageTier();
+
+ public abstract int getMinGlassTier();
+
+ public abstract int getStartingSlotCount();
+
+ public abstract int getSlotPerTierMultiplier();
+
+ public abstract int getSlotCount(int machineTier);
+
+ public abstract int getSeedCapacityPerSlot();
+
+ public abstract int getWeedEXMultiplier();
+
+ public abstract int getMaxFertilizerUsagePerSeed();
+
+ public abstract double getFertilizerBoost();
+
+ public abstract GT_Multiblock_Tooltip_Builder addTooltipInfo(GT_Multiblock_Tooltip_Builder builder);
+
+ /**
+ * Used to resolve factory type to an identifier.
+ */
+ private final HashMap<String, IEIGBucketFactory> factories;
+ /**
+ * A way to have other mods submit custom buckets that can be prioritized over our default buckets
+ */
+ private final LinkedList<IEIGBucketFactory> orderedFactories;
+
+ public EIGMode() {
+ this.factories = new HashMap<>();
+ this.orderedFactories = new LinkedList<>();
+ }
+
+ /**
+ * Adds a bucket factory to the EIG mode and gives it a low priority. Factories with using existing IDs will
+ * overwrite each other.
+ *
+ * @param factory The bucket factory to add.
+ */
+ public void addLowPriorityFactory(IEIGBucketFactory factory) {
+ String factoryId = factory.getNBTIdentifier();
+ dealWithDuplicateFactoryId(factoryId);
+ // add factory as lowest priority
+ this.factories.put(factoryId, factory);
+ this.orderedFactories.addLast(factory);
+ }
+
+ /**
+ * Adds a bucket factory to the EIG mode and gives it a high priority. Factories with using existing IDs will
+ * overwrite each other.
+ *
+ * @param factory The bucket factory to add.
+ */
+ public void addHighPriorityFactory(IEIGBucketFactory factory) {
+ String factoryId = factory.getNBTIdentifier();
+ dealWithDuplicateFactoryId(factoryId);
+ // add factory as lowest priority
+ this.factories.put(factoryId, factory);
+ this.orderedFactories.addFirst(factory);
+ }
+
+ /**
+ * A standardized way to deal with duplicate factory type identifiers.
+ *
+ * @param factoryId The ID of the factory
+ */
+ private void dealWithDuplicateFactoryId(String factoryId) {
+ if (this.factories.containsKey(factoryId)) {
+ // TODO: Check with devs to see if they want a throw instead.
+ error("Duplicate EIG bucket index detected!!!: " + factoryId);
+ // remove duplicate from ordered list
+ this.orderedFactories.remove(this.factories.get(factoryId));
+ }
+ }
+
+ /**
+ * Attempts to create a new bucket from a given item. Returns if the item cannot be inserted into the EIG.
+ *
+ * @see IEIGBucketFactory#tryCreateBucket(GT_MetaTileEntity_ExtremeIndustrialGreenhouse, ItemStack)
+ * @param greenhouse The {@link GT_MetaTileEntity_ExtremeIndustrialGreenhouse} that will contain the seed.
+ * @param input The {@link ItemStack} for the input item.
+ * @param maxConsume The maximum amount of items to consume.
+ * @param simulate Whether to actually consume the seed.
+ * @return Null if no bucket could be created from the item.
+ */
+ public EIGBucket tryCreateNewBucket(GT_MetaTileEntity_ExtremeIndustrialGreenhouse greenhouse, ItemStack input,
+ int maxConsume, boolean simulate) {
+ // Validate inputs
+ if (input == null) return null;
+ maxConsume = Math.min(input.stackSize, maxConsume);
+ if (maxConsume <= 0) return null;
+ for (IEIGBucketFactory factory : this.orderedFactories) {
+ EIGBucket bucket = factory.tryCreateBucket(greenhouse, input);
+ if (bucket == null || !bucket.isValid()) continue;
+ if (!simulate) input.stackSize--;
+ maxConsume--;
+ bucket.tryAddSeed(greenhouse, input, maxConsume, simulate);
+ return bucket;
+ }
+ return null;
+ }
+
+ /**
+ * Restores the buckets of an EIG for the given mode.
+ *
+ * @see IEIGBucketFactory#restore(NBTTagCompound)
+ * @param bucketNBTList The
+ */
+ public void restoreBuckets(NBTTagList bucketNBTList, List<EIGBucket> loadTo) {
+ for (int i = 0; i < bucketNBTList.tagCount(); i++) {
+ // validate nbt
+ NBTTagCompound bucketNBT = bucketNBTList.getCompoundTagAt(i);
+ if (bucketNBT.hasNoTags()) {
+ error("Empty nbt bucket found in EIG nbt.");
+ continue;
+ }
+ if (!bucketNBT.hasKey("type", 8)) {
+ error("Failed to identify bucket type in EIG nbt.");
+ continue;
+ }
+ // identify bucket type
+ String bucketType = bucketNBT.getString("type");
+ IEIGBucketFactory factory = factories.getOrDefault(bucketType, null);
+ if (factory == null) {
+ error("failed to find EIG bucket factory for type: " + bucketType);
+ continue;
+ }
+ // restore bucket
+ loadTo.add(factory.restore(bucketNBT));
+ }
+ }
+}
diff --git a/src/main/java/kubatech/api/eig/IEIGBucketFactory.java b/src/main/java/kubatech/api/eig/IEIGBucketFactory.java
new file mode 100644
index 0000000000..647e544573
--- /dev/null
+++ b/src/main/java/kubatech/api/eig/IEIGBucketFactory.java
@@ -0,0 +1,15 @@
+package kubatech.api.eig;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+
+import kubatech.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeIndustrialGreenhouse;
+
+public interface IEIGBucketFactory {
+
+ String getNBTIdentifier();
+
+ EIGBucket tryCreateBucket(GT_MetaTileEntity_ExtremeIndustrialGreenhouse greenhouse, ItemStack stack);
+
+ EIGBucket restore(NBTTagCompound nbt);
+}