diff options
Diffstat (limited to 'src/main/java/kubatech/api/eig')
-rw-r--r-- | src/main/java/kubatech/api/eig/EIGBucket.java | 247 | ||||
-rw-r--r-- | src/main/java/kubatech/api/eig/EIGDropTable.java | 224 | ||||
-rw-r--r-- | src/main/java/kubatech/api/eig/EIGMode.java | 154 | ||||
-rw-r--r-- | src/main/java/kubatech/api/eig/IEIGBucketFactory.java | 15 |
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); +} |