55import gregtech .api .metatileentity .MTETrait ;
66import gregtech .api .metatileentity .MetaTileEntity ;
77import gregtech .api .metatileentity .multiblock .MultiblockWithDisplayBase ;
8+ import gregtech .api .multiblock .IMaintenance ;
89import gregtech .api .recipes .machines .FuelRecipeMap ;
910import gregtech .api .recipes .recipes .FuelRecipe ;
1011import gregtech .api .util .GTUtility ;
@@ -35,6 +36,7 @@ public class FuelRecipeLogic extends MTETrait implements IControllable, IFuelabl
3536 private boolean isActive ;
3637 private boolean workingEnabled = true ;
3738 private boolean wasActiveAndNeedsUpdate = false ;
39+ protected boolean invalidInputsForRecipes ;
3840
3941 public FuelRecipeLogic (MetaTileEntity metaTileEntity , FuelRecipeMap recipeMap , Supplier <IEnergyContainer > energyContainer , Supplier <IMultipleTankHandler > fluidTank , long maxVoltage ) {
4042 super (metaTileEntity );
@@ -108,20 +110,43 @@ public <T> T getCapability(Capability<T> capability) {
108110 return null ;
109111 }
110112
113+ protected boolean hasNotifiedInputs () {
114+ return metaTileEntity .getNotifiedFluidInputList ().size () > 0 ;
115+ }
116+
117+ protected boolean canWorkWithInputs () {
118+ // if the inputs were bad last time, check if they've changed before trying to find a new recipe.
119+ if (this .invalidInputsForRecipes && !hasNotifiedInputs ()) return false ;
120+ else {
121+ this .invalidInputsForRecipes = false ;
122+ }
123+ return true ;
124+ }
125+
111126 @ Override
112127 public void update () {
113- if (getMetaTileEntity ().getWorld ().isRemote ) return ;
128+ if (getMetaTileEntity ().getWorld ().isRemote ) {
129+ return ;
130+ }
131+
114132 if (workingEnabled ) {
115133 if (recipeDurationLeft > 0 ) {
116- if (energyContainer .get ().getEnergyCanBeInserted () >=
117- recipeOutputVoltage || shouldVoidExcessiveEnergy ()) {
134+ //Check for if the full energy amount can be added to the output container, or if the energy should be voided
135+ //In addition, checks if the recipe should be canceled for any reason (Once per second)
136+ if ((energyContainer .get ().getEnergyCanBeInserted () >= recipeOutputVoltage || shouldVoidExcessiveEnergy ())
137+ && (metaTileEntity .getOffsetTimer () % 20 == 0 && !isObstructed ())) {
118138 energyContainer .get ().addEnergy (recipeOutputVoltage );
139+ //If the recipe has finished, mark the machine as needing to be updated
119140 if (--this .recipeDurationLeft == 0 ) {
120141 this .wasActiveAndNeedsUpdate = true ;
121142 }
122143 }
144+ else if (isObstructed ()) {
145+ this .recipeDurationLeft = 0 ;
146+ this .wasActiveAndNeedsUpdate = true ;
147+ }
123148 }
124- if (recipeDurationLeft == 0 && isReadyForRecipes ()) {
149+ if (recipeDurationLeft == 0 && isReadyForRecipes () && canWorkWithInputs () ) {
125150 tryAcquireNewRecipe ();
126151 }
127152 }
@@ -131,24 +156,50 @@ public void update() {
131156 }
132157 }
133158
159+ /**
160+ * Whether the multiblock can begin searching for new recipes once a recipe is completed.
161+ * This is called only when the multiblock begins searching for new recipes, not during the recipe progression.
162+ * This method will also cancel searching for recipes if there are too many maintenance issues.
163+ *
164+ * @return {@code true} if the multiblock should search for a new recipe
165+ */
134166 protected boolean isReadyForRecipes () {
135- return true ;
167+ if (metaTileEntity instanceof IMaintenance ) {
168+
169+ IMaintenance controller = (IMaintenance ) metaTileEntity ;
170+
171+ // do not run recipes when there are more than 5 maintenance problems
172+ if (controller .hasMaintenanceMechanics () && controller .getNumMaintenanceProblems () > 5 ) {
173+ return false ;
174+ }
175+ }
176+
177+ return !isObstructed ();
178+ }
179+
180+ /**
181+ * Whether the multiblock should cancel its recipe for any reason.
182+ * This will be checked every 20 update ticks, unlike {@link FuelRecipeLogic#isReadyForRecipes()}
183+ * Some examples of usage would be if a rotor or air intake is obstructed.
184+ *
185+ * @return {@code true} if the multiblock should cancel its recipe for any reason
186+ */
187+ protected boolean isObstructed () {
188+ return false ;
136189 }
137190
138191 protected boolean shouldVoidExcessiveEnergy () {
139192 return false ;
140193 }
141194
195+ /**
196+ * Search the combined Fluid Inventory to find a valid fluid for running the power generation recipe.
197+ */
142198 private void tryAcquireNewRecipe () {
143- if (metaTileEntity instanceof MultiblockWithDisplayBase ) {
144-
145- MultiblockWithDisplayBase controller = (MultiblockWithDisplayBase ) metaTileEntity ;
146-
147- // do not run recipes when there are more than 5 maintenance problems
148- if (controller .hasMaintenanceMechanics () && controller .getNumMaintenanceProblems () > 5 )
149- return ;
150- }
151199
200+ // Set this here to avoid it being updated multiple time in the loop through the fluid tanks.
201+ // It will get reset if a valid recipe is found
202+ this .invalidInputsForRecipes = true ;
152203 IMultipleTankHandler fluidTanks = this .fluidTank .get ();
153204 for (IFluidTank fluidTank : fluidTanks ) {
154205 FluidStack tankContents = fluidTank .getFluid ();
@@ -164,15 +215,20 @@ private void tryAcquireNewRecipe() {
164215 if (controller .hasMufflerMechanics ())
165216 controller .outputRecoveryItems ();
166217
167- // increase total on time
218+ // increase total multiblock active time
168219 controller .calculateMaintenance (previousRecipe .getDuration ());
169220 }
170221 }
171222
223+ // If we have successfully found a recipe, update the variable before leaving the loop
224+ this .invalidInputsForRecipes = false ;
172225 break ; //recipe is found and ready to use
173226 }
174227 }
175228 }
229+
230+ // Clear notified Fluid input list, either after successfully finding a recipe, or failure to find a recipe
231+ metaTileEntity .getNotifiedFluidInputList ().clear ();
176232 }
177233
178234 public boolean isActive () {
@@ -181,9 +237,9 @@ public boolean isActive() {
181237
182238 private int tryAcquireNewRecipe (FluidStack fluidStack ) {
183239 FuelRecipe currentRecipe ;
184- if (previousRecipe != null && previousRecipe .matches (getMaxVoltage (), fluidStack )) {
240+ if (this . previousRecipe != null && this . previousRecipe .matches (getMaxVoltage (), fluidStack )) {
185241 //if previous recipe still matches inputs, try to use it
186- currentRecipe = previousRecipe ;
242+ currentRecipe = this . previousRecipe ;
187243 } else {
188244 //else, try searching new recipe for given inputs
189245 currentRecipe = recipeMap .findRecipe (getMaxVoltage (), fluidStack );
@@ -192,9 +248,13 @@ private int tryAcquireNewRecipe(FluidStack fluidStack) {
192248 this .previousRecipe = currentRecipe ;
193249 }
194250 }
251+
252+ //Check if we have found a valid recipe
195253 if (currentRecipe != null && checkRecipe (currentRecipe )) {
196254 int fuelAmountToUse = calculateFuelAmount (currentRecipe );
255+ //Check if we have the required amount of fuel, and optionally boosters
197256 if (fluidStack .amount >= fuelAmountToUse ) {
257+ //Initialize the required variables. This is basically setupRecipe in AbstractRecipeLogic, just condensed
198258 this .recipeDurationLeft = calculateRecipeDuration (currentRecipe );
199259 this .recipeOutputVoltage = startRecipe (currentRecipe , fuelAmountToUse , recipeDurationLeft );
200260 if (wasActiveAndNeedsUpdate ) {
0 commit comments