Skip to content

Skip zero-amount ingredients when computing parallel ratio - #5347

Open
winli84354 wants to merge 1 commit into
GregTechCEu:1.20.1from
winli84354:fix/5289-zero-amount-parallel
Open

Skip zero-amount ingredients when computing parallel ratio#5347
winli84354 wants to merge 1 commit into
GregTechCEu:1.20.1from
winli84354:fix/5289-zero-amount-parallel

Conversation

@winli84354

Copy link
Copy Markdown

What

Fixes #5289.

getMaxParallelRatio divides by each ingredient's required amount to work out how many
parallel runs an inventory can sustain. Nothing filters out ingredients whose amount is
zero, so a recipe carrying a zero-amount input makes the divisor zero and the machine tick
dies with ArithmeticException: / by zero.

GTCEu does not generate zero-amount inputs itself, but nothing rejects them either — the
reporter hit this through OillessGT emitting a recipe with a zero-amount fluid input.

Implementation Details

The divisor comes from the consumables map built at the top of getMaxParallelRatio:

consumables.addTo(ing, amount);                 // amount taken straight from the ingredient
...
final long needed = cEntry.getLongValue();      // can be 0
int ratio = GTMath.saturatedCast(Math.min(limit, available / needed));

I skip these ingredients while the map is being built rather than guarding the division.
An ingredient that requires nothing cannot constrain the parallel count, so keeping it out
of the map is the statement of intent; special-casing it at the division would only
re-derive the same fact further away from the cause. It also matches the
IntCircuitIngredient skip a few lines above in ItemRecipeCapability.

Both capabilities are changed. The issue only reports the fluid path, but
ItemRecipeCapability has the identical division and SizedIngredient#getAmount can
equally return 0, so fixing only fluids would leave the same crash reachable through items.

Zero-amount non-consumables (chance() == 0) are skipped as well. That is a no-op in
behaviour — the satisfaction loop below only fails when needed > 0 — but it keeps both
branches consistent.

AI Usage

  • No AI driven tools were used for this pull request.
  • Yes AI driven tools were used for this pull request.

Agent Used

Claude Code (Claude Fable 5)

Agent Usage Description

The agent read getMaxParallelRatio in both capabilities to confirm the reporter's
diagnosis, noticed that ItemRecipeCapability carries the same defect (which the issue
does not mention), and wrote the two guards and their comments. I reviewed the diff line by
line against the surrounding code, checked the non-consumable reasoning myself, and
verified the build locally.

Outcome

Fixes: #5289

Machines no longer crash when a recipe contains a zero-amount item or fluid input. Such
inputs are ignored for parallel calculation, which is what they already mean semantically.

How Was This Tested

  • compileJava and spotlessJavaCheck both pass locally.
  • The crash path was traced by reading: needed originates from addTo(ing, amount) with
    amount unfiltered, and reaches available / needed unchecked. The guard removes the
    only route by which a zero can enter that map.
  • I checked the non-consumable branch separately: with needed == 0 the satisfaction loop
    computes lesser = min(0, count) = 0, leaves needed at 0, and the needed > 0 test
    never fires — so skipping those is behaviour-preserving, not just crash-avoiding.

I could not reproduce the original OillessGT recipe in-game, so this is not an in-game
verified fix. If a maintainer prefers a regression test over the reasoning above, say so
and I will add one.

Potential Compatibility Issues

None. No API, recipe, item, block, material, or machine changes. The only behavioural
difference is that a zero-amount input no longer participates in the parallel calculation —
previously it crashed, so no existing working setup can depend on the old behaviour.

getMaxParallelRatio divides by each ingredient's required amount to work
out how many parallel runs an inventory can sustain. Nothing filtered out
ingredients whose amount is zero, so such an ingredient became a zero
divisor and killed the machine tick with ArithmeticException.

An ingredient that requires nothing cannot constrain the parallel count,
so keep it out of the consumables map rather than special-casing the
division. This also matches the existing IntCircuitIngredient skip.

Applies to both capabilities: the report is on the fluid path, but
ItemRecipeCapability has the identical division and
SizedIngredient#getAmount can equally return zero.

Fixes GregTechCEu#5289

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@winli84354
winli84354 requested a review from a team as a code owner August 25, 2026 06:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GTRecipeModifiers::hatchParallel throws an ArithmeticException if a recipe has an input with a zero amount

1 participant