Skip to content

Commit

Permalink
"Better Idling" for MTEs (#91)
Browse files Browse the repository at this point in the history
Co-authored-by: Exa <[email protected]>
  • Loading branch information
PrototypeTrousers and Exaxxion authored Aug 21, 2021
1 parent 835b5b9 commit 5c46453
Show file tree
Hide file tree
Showing 28 changed files with 807 additions and 243 deletions.
33 changes: 33 additions & 0 deletions src/main/java/gregtech/api/capability/INotifiableHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package gregtech.api.capability;

import gregtech.api.metatileentity.MetaTileEntity;

/**
* For Item and Fluid handlers capable of notifying entities when
* their contents change
*/
public interface INotifiableHandler {

/**
* Adds the notified handler to the notified list
*
* @param isExport boolean specifying if a handler is an output handler
*/

default <T> void addToNotifiedList(MetaTileEntity metaTileEntity, T handler, boolean isExport) {
if (metaTileEntity != null && metaTileEntity.isValid()) {
if (isExport) {
metaTileEntity.addNotifiedOutput(handler);
} else {
metaTileEntity.addNotifiedInput(handler);
}
}
}

/**
* @param metaTileEntity MetaTileEntity to be notified
*/
default void setNotifiableMetaTileEntity(MetaTileEntity metaTileEntity) {

}
}
148 changes: 86 additions & 62 deletions src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.NonNullList;
import net.minecraft.world.*;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fluids.FluidStack;
Expand All @@ -24,7 +25,6 @@
import net.minecraftforge.items.IItemHandlerModifiable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.LongSupplier;
Expand All @@ -37,8 +37,8 @@ public abstract class AbstractRecipeLogic extends MTETrait implements IWorkable
public final RecipeMap<?> recipeMap;

protected boolean forceRecipeRecheck;
protected ItemStack[] lastItemInputs;
protected FluidStack[] lastFluidInputs;
@Deprecated protected ItemStack[] lastItemInputs;
@Deprecated protected FluidStack[] lastFluidInputs;
protected Recipe previousRecipe;
protected boolean allowOverclocking = true;
private long overclockVoltage = 0;
Expand All @@ -55,6 +55,8 @@ public abstract class AbstractRecipeLogic extends MTETrait implements IWorkable
protected boolean workingEnabled = true;
protected boolean hasNotEnoughEnergy;
protected boolean wasActiveAndNeedsUpdate;
protected boolean isOutputsFull;
protected boolean invalidInputsForRecipes;

protected boolean hasPerfectOC = false;

Expand Down Expand Up @@ -115,12 +117,14 @@ public <T> T getCapability(Capability<T> capability) {

@Override
public void update() {
if (!getMetaTileEntity().getWorld().isRemote) {
World world = getMetaTileEntity().getWorld();
if (world != null && !world.isRemote) {
if (workingEnabled) {
if (progressTime > 0) {
updateRecipeProgress();
}
if (progressTime == 0) {
//check everything that would make a recipe never start here.
if (progressTime == 0 && shouldSearchForRecipes()) {
trySearchNewRecipe();
}
}
Expand All @@ -131,6 +135,40 @@ public void update() {
}
}

protected boolean shouldSearchForRecipes() {
return canWorkWithInputs() && canFitNewOutputs();
}

protected boolean hasNotifiedInputs() {
return (metaTileEntity.getNotifiedItemInputList().size() > 0 ||
metaTileEntity.getNotifiedFluidInputList().size() > 0);
}

protected boolean hasNotifiedOutputs() {
return (metaTileEntity.getNotifiedItemOutputList().size() > 0 ||
metaTileEntity.getNotifiedFluidOutputList().size() > 0);
}

protected boolean canFitNewOutputs() {
// if the output is full check if the output changed so we can process recipes results again.
if (this.isOutputsFull && !hasNotifiedOutputs()) return false;
else {
this.isOutputsFull = false;
metaTileEntity.getNotifiedItemOutputList().clear();
metaTileEntity.getNotifiedFluidOutputList().clear();
}
return true;
}

protected boolean canWorkWithInputs() {
// if the inputs were bad last time, check if they've changed before trying to find a new recipe.
if (this.invalidInputsForRecipes && !hasNotifiedInputs()) return false;
else {
this.invalidInputsForRecipes = false;
}
return true;
}

protected void updateRecipeProgress() {
boolean drawEnergy = drawEnergy(recipeEUt);
if (drawEnergy || (recipeEUt < 0)) {
Expand Down Expand Up @@ -158,23 +196,26 @@ protected void trySearchNewRecipe() {
Recipe currentRecipe = null;
IItemHandlerModifiable importInventory = getInputInventory();
IMultipleTankHandler importFluids = getInputTank();
if (previousRecipe != null && previousRecipe.matches(false, importInventory, importFluids)) {
//if previous recipe still matches inputs, try to use it
currentRecipe = previousRecipe;
} else {
boolean dirty = checkRecipeInputsDirty(importInventory, importFluids);
if (dirty || forceRecipeRecheck) {
this.forceRecipeRecheck = false;
//else, try searching new recipe for given inputs
currentRecipe = findRecipe(maxVoltage, importInventory, importFluids, MatchingMode.DEFAULT);
if (currentRecipe != null) {
this.previousRecipe = currentRecipe;
}
}

// see if the last recipe we used still works
if (this.previousRecipe != null && this.previousRecipe.matches(false, importInventory, importFluids))
currentRecipe = this.previousRecipe;
// If there is no active recipe, then we need to find one.
else {
currentRecipe = findRecipe(maxVoltage, importInventory, importFluids, MatchingMode.DEFAULT);
}
if (currentRecipe != null && setupAndConsumeRecipeInputs(currentRecipe)) {
setupRecipe(currentRecipe);
// If a recipe was found, then inputs were valid. Cache found recipe.
if (currentRecipe != null) {
this.previousRecipe = currentRecipe;
}
this.invalidInputsForRecipes = (currentRecipe == null);

// proceed if we have a usable recipe.
if (currentRecipe != null && setupAndConsumeRecipeInputs(currentRecipe))
setupRecipe(currentRecipe);
// Inputs have been inspected.
metaTileEntity.getNotifiedItemInputList().clear();
metaTileEntity.getNotifiedFluidInputList().clear();
}

public void forceRecipeRecheck() {
Expand All @@ -196,40 +237,16 @@ protected Recipe findRecipe(long maxVoltage, IItemHandlerModifiable inputs, IMul
return recipeMap.findRecipe(maxVoltage, inputs, fluidInputs, getMinTankCapacity(getOutputTank()), mode);
}

/**
* @deprecated Use {@link #hasNotifiedInputs() } instead
* Left here for binary compatibility purposes
*/
@Deprecated
protected boolean checkRecipeInputsDirty(IItemHandler inputs, IMultipleTankHandler fluidInputs) {
boolean shouldRecheckRecipe = false;
if (lastItemInputs == null || lastItemInputs.length != inputs.getSlots()) {
this.lastItemInputs = new ItemStack[inputs.getSlots()];
Arrays.fill(lastItemInputs, ItemStack.EMPTY);
}
if (lastFluidInputs == null || lastFluidInputs.length != fluidInputs.getTanks()) {
this.lastFluidInputs = new FluidStack[fluidInputs.getTanks()];
}
for (int i = 0; i < lastItemInputs.length; i++) {
ItemStack currentStack = inputs.getStackInSlot(i);
ItemStack lastStack = lastItemInputs[i];
if (!areItemStacksEqual(currentStack, lastStack)) {
this.lastItemInputs[i] = currentStack.isEmpty() ? ItemStack.EMPTY : currentStack.copy();
shouldRecheckRecipe = true;
} else if (currentStack.getCount() != lastStack.getCount()) {
lastStack.setCount(currentStack.getCount());
shouldRecheckRecipe = true;
}
}
for (int i = 0; i < lastFluidInputs.length; i++) {
FluidStack currentStack = fluidInputs.getTankAt(i).getFluid();
FluidStack lastStack = lastFluidInputs[i];
if ((currentStack == null && lastStack != null) ||
(currentStack != null && !currentStack.isFluidEqual(lastStack))) {
this.lastFluidInputs[i] = currentStack == null ? null : currentStack.copy();
shouldRecheckRecipe = true;
} else if (currentStack != null && lastStack != null &&
currentStack.amount != lastStack.amount) {
lastStack.amount = currentStack.amount;
shouldRecheckRecipe = true;
}
}
return shouldRecheckRecipe;
boolean isDirty = this.hasNotifiedInputs();
metaTileEntity.getNotifiedItemInputList().clear();
metaTileEntity.getNotifiedFluidInputList().clear();
return isDirty;
}

protected static boolean areItemStacksEqual(ItemStack stackA, ItemStack stackB) {
Expand All @@ -245,11 +262,20 @@ protected boolean setupAndConsumeRecipeInputs(Recipe recipe) {
IItemHandlerModifiable exportInventory = getOutputInventory();
IMultipleTankHandler importFluids = getInputTank();
IMultipleTankHandler exportFluids = getOutputTank();
return (totalEUt >= 0 ? getEnergyStored() >= (totalEUt > getEnergyCapacity() / 2 ? resultOverclock[0] : totalEUt) :
(getEnergyStored() - resultOverclock[0] <= getEnergyCapacity())) &&
MetaTileEntity.addItemsToItemHandler(exportInventory, true, recipe.getAllItemOutputs(exportInventory.getSlots())) &&
MetaTileEntity.addFluidsToFluidHandler(exportFluids, true, recipe.getFluidOutputs()) &&
recipe.matches(true, importInventory, importFluids);
if (!(totalEUt >= 0 ? getEnergyStored() >= (totalEUt > getEnergyCapacity() / 2 ? resultOverclock[0] : totalEUt) :
(getEnergyStored() - resultOverclock[0] <= getEnergyCapacity()))) {
return false;
}
if (!MetaTileEntity.addItemsToItemHandler(exportInventory, true, recipe.getAllItemOutputs(exportInventory.getSlots()))) {
this.isOutputsFull = true;
return false;
}
if (!MetaTileEntity.addFluidsToFluidHandler(exportFluids, true, recipe.getFluidOutputs())) {
this.isOutputsFull = true;
return false;
}
this.isOutputsFull = false;
return recipe.matches(true, importInventory, importFluids);
}

protected int[] calculateOverclock(int EUt, int duration) {
Expand Down Expand Up @@ -329,9 +355,6 @@ protected void completeRecipe() {
this.itemOutputs = null;
this.hasNotEnoughEnergy = false;
this.wasActiveAndNeedsUpdate = true;
//force recipe recheck because inputs could have changed since last time
//we checked them before starting our recipe, especially if recipe took long time
this.forceRecipeRecheck = true;
}

public double getProgressPercent() {
Expand Down Expand Up @@ -364,7 +387,8 @@ public void setMaxProgress(int maxProgress) {
protected void setActive(boolean active) {
this.isActive = active;
metaTileEntity.markDirty();
if (!metaTileEntity.getWorld().isRemote) {
World world = metaTileEntity.getWorld();
if (world != null && !world.isRemote) {
writeCustomData(1, buf -> buf.writeBoolean(active));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package gregtech.api.capability.impl;

import gregtech.api.capability.INotifiableHandler;
import gregtech.api.metatileentity.MetaTileEntity;

public class NotifiableFilteredFluidHandler extends FilteredFluidHandler implements INotifiableHandler {

MetaTileEntity notifiableEntity;
private final boolean isExport;

public NotifiableFilteredFluidHandler(int capacity, MetaTileEntity entityToNotify, boolean isExport) {
super(capacity);
this.notifiableEntity = entityToNotify;
this.isExport = isExport;
}

@Override
protected void onContentsChanged() {
super.onContentsChanged();
addToNotifiedList(notifiableEntity, this, isExport);
}

@Override
public void setNotifiableMetaTileEntity(MetaTileEntity metaTileEntity) {
this.notifiableEntity = metaTileEntity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package gregtech.api.capability.impl;

import gregtech.api.capability.INotifiableHandler;
import gregtech.api.metatileentity.MetaTileEntity;
import net.minecraftforge.fluids.FluidTank;

public class NotifiableFluidTank extends FluidTank implements INotifiableHandler {

MetaTileEntity notifiableEntity;
private final boolean isExport;

public NotifiableFluidTank(int capacity, MetaTileEntity entityToNotify, boolean isExport) {
super(capacity);
this.notifiableEntity = entityToNotify;
this.isExport = isExport;
}

@Override
protected void onContentsChanged() {
super.onContentsChanged();
addToNotifiedList(notifiableEntity, this, isExport);
}

@Override
public void setNotifiableMetaTileEntity(MetaTileEntity metaTileEntity) {
this.notifiableEntity = metaTileEntity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package gregtech.api.capability.impl;

import gregtech.api.capability.INotifiableHandler;
import gregtech.api.metatileentity.MetaTileEntity;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemStackHandler;

public class NotifiableItemStackHandler extends ItemStackHandler implements IItemHandlerModifiable, INotifiableHandler {

MetaTileEntity notifiableEntity;
private final boolean isExport;

public NotifiableItemStackHandler(int slots, MetaTileEntity entityToNotify, boolean isExport) {
super(slots);
this.notifiableEntity = entityToNotify;
this.isExport = isExport;
}

@Override
public void onContentsChanged(int slot) {
super.onContentsChanged(slot);
addToNotifiedList(notifiableEntity, this, isExport);
}

@Override
public void setNotifiableMetaTileEntity(MetaTileEntity metaTileEntity) {
this.notifiableEntity = metaTileEntity;
}
}
Loading

0 comments on commit 5c46453

Please sign in to comment.