Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better idling for metatileentities and multiblocks #1554

Open
wants to merge 26 commits into
base: master
Choose a base branch
from

Conversation

PrototypeTrousers
Copy link
Contributor

What:
This PR is my attempt on the issue of gregtech machines being "laggy" when actually idling with full inputs and outputs.
I've iterated this concept a some times and i think its good so here it is.

How solved:
implemented checks in the Abstract recipe logic for inputs (if a valid recipe can be made out of them) and outputs (if its full, and we cant accept a recipe because of it, wait for the output to make some space before looping unsuccessfully)
implemented fluid and item handlers that can change those settings by notifying the metatileentity that its inventory changed.

Outcome:
GTCE single and multiblock machines will idle with a input of partial ingredients and when its outputs are full.

Additional info:
By avoiding recipe lookups when the inputs dont make a valid recipe, and by avoiding simulating merging items that we cant push into the output, we can save some tick time for other stuff

Possible compatibility issue:
Included tests that match the expected behaviour of a chemical reactor ( made by @exa ) and a blast furnace.
the outputfull is set on the addItemsToItemHandler method, and checked for in the new method shouldSearchForRecipes, so will work immediatelly.
the inputsinvalidation flag should be set o the method that actually returns the Recipe object, and may need implementation on their part, but should not be too much work.

Copy link
Member

@LAGIdiot LAGIdiot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your hard work. From functional point it looks solid. I have some questions regarding implementation and other comments to places which needs adjustments.

Also there is problem with code formatting. As we are providing formatting in .editorconfig I would suggest you to apply it or I may ignore additional PRs without proper formatting (and yes I am that type of person).

@LAGIdiot LAGIdiot added rsr: minor Release size requirements: Minor type: feature New feature or request labels Mar 31, 2021
@PrototypeTrousers PrototypeTrousers force-pushed the RecipeLogic branch 2 times, most recently from e471d92 to cd3e063 Compare March 31, 2021 18:53
Copy link
Collaborator

@ALongStringOfNumbers ALongStringOfNumbers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spent a brief time looking this over, and left a small number of comments.

In addition to the comments left on the PR, I noticed some weird behavior while testing in game.

When testing on multiblocks, the front face was not lighting up green as should when the multiblock becomes active. This occurred for both the Multismelter and the EBF, so I expect somewhere that isActive is not being properly updated.

@PrototypeTrousers PrototypeTrousers force-pushed the RecipeLogic branch 3 times, most recently from a32225b to 15feb38 Compare May 29, 2021 01:58
@LAGIdiot
Copy link
Member

Thanks for updating this. Can you please fix formatting of all edited files as it does not conform our style. IntelliJ IDEA should be able to do it perfectly as we are providing .editorconfig file.

@LAGIdiot
Copy link
Member

LAGIdiot commented Jun 5, 2021

This looks quite solid to me. Anyone from Addons do you see any glaring problems that this could cause to you?
Also this is candidate for early sprint merging as it will need lot of testing and would be great to get it finished soon because with every release there are conflicts which needs to be fixed which I believe is quite excruciating.

@LAGIdiot LAGIdiot added the early merge adept Adept for merge early in release cycle for longer testing period label Jun 5, 2021
Copy link
Collaborator

@ALongStringOfNumbers ALongStringOfNumbers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more things brought up in looking this over.

@@ -198,9 +205,12 @@ protected Recipe findRecipe(long maxVoltage,
}

// If there were no accepted ingredients, then there is no recipe to process.
if(recipeInputs.isEmpty()) {
// the output may be filled up
if (recipeInputs.isEmpty() && !invalidInputsForRecipes) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only case where !invalidInputsForRecipes would be true is when a matching recipe exists, and so the recipe inputs would not be empty, so this logic doesn't quite make sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the output is full ( so canFit is false ) for that recipe, we exit the loop before adding to recipeInputs.
in that case, an empty recipeInputs does not mean that there are no valid input, it means we could not add anything because the output is full.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, we could have iterated through the for loop once first, which would set the state of invalidInputsForRecipes. It might be a good idea to reset the value of invalidInputsForRecipes if the check for canFitOutputs passes, but before the break out of the loop.

@ALongStringOfNumbers
Copy link
Collaborator

For addons, this might cause some issues with @DStrand1 's Distinct Input bus implementation found in Gregicality (Initial PR done here GregTechCEu/gregicality-legacy#451), although I will leave it up to him to review this and see if he can rework the distinct bus implementation based on the changes in this PR, and if he has any other concerns.

It may be interesting to implement distinct buses directly in GTCE, as although GTCE multiblocks could not make much use of it, especially since there are no Large Machine Multiblocks as there are in Gregicality, having a unified implementation may make it easier for addons to implement it, and integrate it with the changes done to GTCE logic.

PrototypeTrousers and others added 14 commits July 22, 2021 17:31
takes in consideration the result of the last iteration when:
1. no recipe found for current items in inputInventory.
2. if the recipe found cant push its result due to lack of space in the outputinventory.
avoids copying itemstacks that are at max size, and cant be merged into anyway
can notify controllers/metatileentities of inventory changes
recipe logic can wait for changes to the output if it cant process recipes if the output is full. can also wait for changes in the input inventory in case a recipe was searched for but didnt result in a valid recipe.
implemented tests. one simulates a chemical reactor, the other one an electric blast furnace
restored cover field as final
deprecated old arrays
moved method to protected
add java doc for deprecated checkRecipeInputsDirty
renamed variables from single to plural for more clarity
added instance checks before casting
reformatted javadoc
re-based
@warjort
Copy link
Contributor

warjort commented Jul 26, 2021

Sorry to be late to the party on this.

I have a few comments, the first is a longish diff.
It basically makes 2 changes.

  • It replaces the lists of modified handlers with booleans in MetaTileEntity
    The only thing that was being done with these lists was x.add(), x.clear() and x.size() > 0 which is isomorphic to x = true, x = false, x == true

  • It makes the passing of the notification handler around more implicit.
    The handler is only ever "this" currently. Is there a use case where it would be something else?
    I also think isExport could be implicit as well if isExport() was part of the INotifiableHandler interface and implemented on the 3 handlers from their internal fields. I didn't change this though.
    Is there any use case where isExportHatch on the multipart bus/hatch doesn't match isExport on the handler?

Here is the diff:

diff --git a/src/main/java/gregtech/api/capability/INotifiableHandler.java b/src/main/java/gregtech/api/capability/INotifiableHandler.java
index 34cf1c36..f6badc9b 100644
--- a/src/main/java/gregtech/api/capability/INotifiableHandler.java
+++ b/src/main/java/gregtech/api/capability/INotifiableHandler.java
@@ -14,12 +14,12 @@ public interface INotifiableHandler {
      * @param isExport boolean specifying if a handler is an output handler
      */
 
-    default <T> void addToNotifiedList(MetaTileEntity metaTileEntity, T handler, boolean isExport) {
+    default void addToNotifiedList(MetaTileEntity metaTileEntity, boolean isExport) {
         if (metaTileEntity != null && metaTileEntity.isValid()) {
             if (isExport) {
-                metaTileEntity.addNotifiedOutput(handler);
+                metaTileEntity.addNotifiedOutput(this);
             } else {
-                metaTileEntity.addNotifiedInput(handler);
+                metaTileEntity.addNotifiedInput(this);
             }
         }
     }
diff --git a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java
index c8504522..1048b34b 100755
--- a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java
+++ b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java
@@ -131,13 +131,13 @@ public abstract class AbstractRecipeLogic extends MTETrait implements IWorkable
     }
 
     protected boolean hasNotifiedInputs() {
-        return (metaTileEntity.getNotifiedItemInputList().size() > 0 ||
-                metaTileEntity.getNotifiedFluidInputList().size() > 0);
+        return (metaTileEntity.isNotifiedItemInput() ||
+                metaTileEntity.isNotifiedFluidInput());
     }
 
     protected boolean hasNotifiedOutputs() {
-        return (metaTileEntity.getNotifiedItemOutputList().size() > 0 ||
-                metaTileEntity.getNotifiedFluidOutputList().size() > 0);
+        return (metaTileEntity.isNotifiedItemOutput() ||
+                metaTileEntity.isNotifiedFluidOutput());
     }
 
     protected boolean canFitNewOutputs() {
@@ -145,8 +145,8 @@ public abstract class AbstractRecipeLogic extends MTETrait implements IWorkable
         if (this.isOutputsFull && !hasNotifiedOutputs()) return false;
         else {
             this.isOutputsFull = false;
-            metaTileEntity.getNotifiedItemOutputList().clear();
-            metaTileEntity.getNotifiedFluidOutputList().clear();
+            metaTileEntity.resetNotifiedItemOutput();
+            metaTileEntity.resetNotifiedFluidOutput();
         }
         return true;
     }
@@ -205,8 +205,8 @@ public abstract class AbstractRecipeLogic extends MTETrait implements IWorkable
         if (currentRecipe != null && setupAndConsumeRecipeInputs(currentRecipe))
             setupRecipe(currentRecipe);
         // Inputs have been inspected.
-        metaTileEntity.getNotifiedItemInputList().clear();
-        metaTileEntity.getNotifiedFluidInputList().clear();
+        metaTileEntity.resetNotifiedItemInput();
+        metaTileEntity.resetNotifiedFluidInput();
     }
 
     public void forceRecipeRecheck() {
@@ -235,8 +235,8 @@ public abstract class AbstractRecipeLogic extends MTETrait implements IWorkable
     @Deprecated
     protected boolean checkRecipeInputsDirty(IItemHandler inputs, IMultipleTankHandler fluidInputs) {
         boolean isDirty = this.hasNotifiedInputs();
-        metaTileEntity.getNotifiedItemInputList().clear();
-        metaTileEntity.getNotifiedFluidInputList().clear();
+        metaTileEntity.resetNotifiedItemInput();
+        metaTileEntity.resetNotifiedFluidInput();
         return isDirty;
     }
 
diff --git a/src/main/java/gregtech/api/capability/impl/NotifiableFilteredFluidHandler.java b/src/main/java/gregtech/api/capability/impl/NotifiableFilteredFluidHandler.java
index 7e5d3ab4..db4ee451 100644
--- a/src/main/java/gregtech/api/capability/impl/NotifiableFilteredFluidHandler.java
+++ b/src/main/java/gregtech/api/capability/impl/NotifiableFilteredFluidHandler.java
@@ -17,7 +17,7 @@ public class NotifiableFilteredFluidHandler extends FilteredFluidHandler impleme
     @Override
     protected void onContentsChanged() {
         super.onContentsChanged();
-        addToNotifiedList(notifiableEntity, this, isExport);
+        addToNotifiedList(notifiableEntity, isExport);
     }
 
     @Override
diff --git a/src/main/java/gregtech/api/capability/impl/NotifiableFluidTank.java b/src/main/java/gregtech/api/capability/impl/NotifiableFluidTank.java
index 2c54e096..9aa141e4 100644
--- a/src/main/java/gregtech/api/capability/impl/NotifiableFluidTank.java
+++ b/src/main/java/gregtech/api/capability/impl/NotifiableFluidTank.java
@@ -18,7 +18,7 @@ public class NotifiableFluidTank extends FluidTank implements INotifiableHandler
     @Override
     protected void onContentsChanged() {
         super.onContentsChanged();
-        addToNotifiedList(notifiableEntity, this, isExport);
+        addToNotifiedList(notifiableEntity, isExport);
     }
 
     @Override
diff --git a/src/main/java/gregtech/api/capability/impl/NotifiableItemStackHandler.java b/src/main/java/gregtech/api/capability/impl/NotifiableItemStackHandler.java
index 88e3c58e..4858287e 100644
--- a/src/main/java/gregtech/api/capability/impl/NotifiableItemStackHandler.java
+++ b/src/main/java/gregtech/api/capability/impl/NotifiableItemStackHandler.java
@@ -17,9 +17,9 @@ public class NotifiableItemStackHandler extends ItemStackHandler implements IIte
     }
 
     @Override
-    public void onContentsChanged(int slot) {
+    protected void onContentsChanged(int slot) {
         super.onContentsChanged(slot);
-        addToNotifiedList(notifiableEntity, this, isExport);
+        addToNotifiedList(notifiableEntity, isExport);
     }
 
     @Override
diff --git a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java
index 2c457529..d94462d4 100644
--- a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java
+++ b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java
@@ -88,10 +88,10 @@ public abstract class MetaTileEntity implements ICoverable {
     protected boolean isFragile = false;
 
     private final CoverBehavior[] coverBehaviors = new CoverBehavior[6];
-    protected List<IItemHandlerModifiable> notifiedItemOutputList = new ArrayList<>();
-    protected List<IItemHandlerModifiable> notifiedItemInputList = new ArrayList<>();
-    protected List<IFluidHandler> notifiedFluidInputList = new ArrayList<>();
-    protected List<IFluidHandler> notifiedFluidOutputList = new ArrayList<>();
+    protected boolean notifiedItemOutput = false;
+    protected boolean notifiedItemInput = false;
+    protected boolean notifiedFluidInput = false;
+    protected boolean notifiedFluidOutput = false;
 
     public MetaTileEntity(ResourceLocation metaTileEntityId) {
         this.metaTileEntityId = metaTileEntityId;
@@ -261,25 +261,17 @@ public abstract class MetaTileEntity implements ICoverable {
 
     public <T> void addNotifiedInput(T input) {
         if (input instanceof IItemHandlerModifiable) {
-            if (!notifiedItemInputList.contains(input)) {
-                this.notifiedItemInputList.add((IItemHandlerModifiable) input);
-            }
+            this.notifiedItemInput = true;
         } else if (input instanceof FluidTank) {
-            if (!notifiedFluidInputList.contains(input)) {
-                this.notifiedFluidInputList.add((FluidTank) input);
-            }
+            this.notifiedFluidInput = true;
         }
     }
 
     public <T> void addNotifiedOutput(T output) {
         if (output instanceof IItemHandlerModifiable) {
-            if (!notifiedItemOutputList.contains(output)) {
-                this.notifiedItemOutputList.add((IItemHandlerModifiable) output);
-            }
+            this.notifiedItemOutput = true;
         } else if (output instanceof NotifiableFluidTank) {
-            if (!notifiedFluidOutputList.contains(output)) {
-                this.notifiedFluidOutputList.add((NotifiableFluidTank) output);
-            }
+            this.notifiedFluidOutput = true;
         }
     }
 
@@ -1239,20 +1231,36 @@ public abstract class MetaTileEntity implements ICoverable {
         return exportFluids;
     }
 
-    public List<IItemHandlerModifiable> getNotifiedItemOutputList() {
-        return notifiedItemOutputList;
+    public boolean isNotifiedItemOutput() {
+        return this.notifiedItemOutput;
+    }
+
+    public boolean isNotifiedItemInput() {
+        return this.notifiedItemInput;
+    }
+
+    public boolean isNotifiedFluidInput() {
+        return this.notifiedFluidInput;
+    }
+
+    public boolean isNotifiedFluidOutput() {
+        return this.notifiedFluidOutput;
+    }
+
+    public void resetNotifiedItemOutput() {
+        this.notifiedItemOutput = false;
     }
 
-    public List<IItemHandlerModifiable> getNotifiedItemInputList() {
-        return notifiedItemInputList;
+    public void resetNotifiedItemInput() {
+        this.notifiedItemInput = false;
     }
 
-    public List<IFluidHandler> getNotifiedFluidInputList() {
-        return notifiedFluidInputList;
+    public void resetNotifiedFluidInput() {
+        this.notifiedFluidInput = false;
     }
 
-    public List<IFluidHandler> getNotifiedFluidOutputList() {
-        return notifiedFluidOutputList;
+    public void resetNotifiedFluidOutput() {
+        this.notifiedFluidOutput = false;
     }
 
     public boolean isFragile() {
diff --git a/src/main/java/gregtech/common/metatileentities/electric/multiblockpart/MetaTileEntityFluidHatch.java b/src/main/java/gregtech/common/metatileentities/electric/multiblockpart/MetaTileEntityFluidHatch.java
index 1664c39e..526ce7aa 100644
--- a/src/main/java/gregtech/common/metatileentities/electric/multiblockpart/MetaTileEntityFluidHatch.java
+++ b/src/main/java/gregtech/common/metatileentities/electric/multiblockpart/MetaTileEntityFluidHatch.java
@@ -130,7 +130,7 @@ public class MetaTileEntityFluidHatch extends MetaTileEntityMultiblockPart imple
         }
         if (handler != null) {
             handler.setNotifiableMetaTileEntity(metaTileEntity);
-            handler.addToNotifiedList(this, handler, isExportHatch);
+            handler.addToNotifiedList(this, this.isExportHatch);
         }
     }
 
diff --git a/src/main/java/gregtech/common/metatileentities/electric/multiblockpart/MetaTileEntityItemBus.java b/src/main/java/gregtech/common/metatileentities/electric/multiblockpart/MetaTileEntityItemBus.java
index 39783c00..fe52029d 100644
--- a/src/main/java/gregtech/common/metatileentities/electric/multiblockpart/MetaTileEntityItemBus.java
+++ b/src/main/java/gregtech/common/metatileentities/electric/multiblockpart/MetaTileEntityItemBus.java
@@ -99,7 +99,7 @@ public class MetaTileEntityItemBus extends MetaTileEntityMultiblockPart implemen
         }
         if (handler != null) {
             handler.setNotifiableMetaTileEntity(metaTileEntity);
-            handler.addToNotifiedList(this, handler, isExportHatch);
+            handler.addToNotifiedList(this, this.isExportHatch);
         }
     }
 
diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiFurnace.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiFurnace.java
index 1651bc56..c6e18997 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiFurnace.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiFurnace.java
@@ -126,7 +126,7 @@ public class MetaTileEntityMultiFurnace extends RecipeMapMultiblockController {
             if (currentRecipe != null && setupAndConsumeRecipeInputs(currentRecipe))
                 setupRecipe(currentRecipe);
             // Inputs have been inspected.
-            metaTileEntity.getNotifiedItemInputList().clear();
+            metaTileEntity.resetNotifiedItemInput();
         }
 
         @Override

@@ -257,6 +259,30 @@ public final String getMetaFullName() {
return getMetaName() + ".name";
}

public <T> void addNotifiedInput(T input) {
Copy link
Contributor

@warjort warjort Jul 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not understanding the logic here?

Why do items use the top level class IItemHandlerModifiable
while the fluids use FluidTank and NotifiableFluidTank.

Why don't the fluids use the IFluidHandler top level class?

}
}

public <T> void addNotifiedOutput(T output) {
Copy link
Contributor

@warjort warjort Jul 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameterized type on this and the addNotifiedInput() does nothing?
It could just be replaced with Object.
You are using instanceof and cast on the parameter anyway.

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this really be a default method?
Is there a case where an implementing class doesn't implement this method?

@warjort
Copy link
Contributor

warjort commented Jul 26, 2021

Unfortunately, I don't know much about the AbstractRecipeLogic class which is the important change in this PR.
So I can't really offer any insights there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
early merge adept Adept for merge early in release cycle for longer testing period rsr: minor Release size requirements: Minor type: feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants