GregTechCEu / GregTech-Modern

GregTech CE Unofficial for modern versions
GNU Lesser General Public License v3.0
268 stars 162 forks source link

Overclock Logic with Subtick Parallel Is Wrong #1487

Closed YiRanMushroom closed 3 months ago

YiRanMushroom commented 3 months ago

Checked for existing issues

Tested latest version

GregTech CEu Version

1.3.0-a-build_833

Recipe Viewer Installed

None

Environment

Singleplayer

Cross-Mod Interaction

No

Other Installed Mods

Only testing this mod.

Expected Behavior

We hope that the overclock logic can work.

Actual Behavior

The Overclock Logic with Subtick Parallel is wrong, which means that when using this logic, overclocking cannot perform. This is because of this part of the code in GTRecipeModifiers:

public static GTRecipe subtickParallel(MetaMachine machine, @NotNull GTRecipe recipe, boolean modifyDuration) {
        if (machine instanceof WorkableElectricMultiblockMachine electricMachine) {
            final Pair<GTRecipe, Integer>[] result = new Pair[] { null };
            RecipeHelper.applyOverclock(
                    new OverclockingLogic((recipe1, recipeEUt, maxVoltage, duration, amountOC) -> {
                        var parallel = OverclockingLogic.standardOverclockingLogicWithSubTickParallelCount(
                                Math.abs(recipeEUt),
                                maxVoltage,
                                duration,
                                amountOC,
                                OverclockingLogic.STANDARD_OVERCLOCK_DURATION_DIVISOR,
                                OverclockingLogic.STANDARD_OVERCLOCK_VOLTAGE_MULTIPLIER);

                        result[0] = GTRecipeModifiers.accurateParallel(machine, recipe, parallel.getRight(),
                                modifyDuration);
                        return LongIntPair.of(parallel.getLeft(), parallel.getMiddle());
                    }), recipe, electricMachine.getOverclockVoltage());
            if (result[0] != null) {
                return result[0].getFirst();
            }
        }
        return null;
    }

You can see that The return value of RecipeHelper.applyOverclock is voided, and the modifier of duration and EUt happens in applyOverclock, so result cannot be modifiered there because it is only captured in the lambda.

And also, in parameters of applyOverclock, we should also not use recipe as second parameter since we want it to modify the recipe after the parallel.

My solution is like this, definately not perfect but it works, I suggest that we should try to inline all operations in the method, rather than calling other methods since the logic is very unique.

First, I created a new function, you may want to see how we can use this function first below, and then the definition, or it really does not seem to make sense:

public static GTRecipe applyOverclock(OverclockingLogic logic, Supplier<GTRecipe> recipeSupplier, long maxOverclockVoltage) {
        GTRecipe recipe = null;
        long EUt = getInputEUt(recipeSupplier.get());
        if (EUt > 0) {
            var overclockResult = performOverclocking(logic, recipeSupplier.get(), EUt, maxOverclockVoltage);
            if (overclockResult.leftLong() != EUt || recipeSupplier.get().duration != overclockResult.rightInt()) {
                recipe = recipeSupplier.get().copy();
                recipe.duration = overclockResult.rightInt();
                for (Content content : recipe.getTickInputContents(EURecipeCapability.CAP)) {
                    content.content = overclockResult.leftLong();
                }
            }
        }
        return recipe;
    }

I didn't considered about the case wen EUt < 0 because I think that is never gonna happen, and the overclocking logic should never be applied twice.

And this is the way we should call the function:

public static GTRecipe subtickParallel(MetaMachine machine, @NotNull GTRecipe recipe, boolean modifyDuration) {
        if (machine instanceof WorkableElectricMultiblockMachine electricMachine) {
            final Pair<GTRecipe, Integer>[] result = new Pair[] { null };
            return applyOverclock(
                new OverclockingLogic((recipe1, recipeEUt, maxVoltage, duration, amountOC) -> {
                    var parallel = OverclockingLogic.standardOverclockingLogicWithSubTickParallelCount(
                        Math.abs(recipeEUt),
                        maxVoltage,
                        duration,
                        amountOC,
                        OverclockingLogic.STANDARD_OVERCLOCK_DURATION_DIVISOR,
                        OverclockingLogic.STANDARD_OVERCLOCK_VOLTAGE_MULTIPLIER);

                    result[0] = GTRecipeModifiers.accurateParallel(machine, recipe, parallel.getRight(),
                        modifyDuration);
                    return LongIntPair.of(parallel.getLeft(), parallel.getMiddle());
                }), () -> result[0] == null ? recipe : result[0].getFirst(), electricMachine.getOverclockVoltage());
        }
        return null;
    }

Steps to Reproduce

Very easy to, just try one recipe.

Additional Information

Consider redesign the subtickParallel completely because I really don't think there would be a clean way to do this using RecipeHelpers.applyOverclock

YiRanMushroom commented 3 months ago

Just found out I miss understood the code, sorry. It is correct, I wrote something wrong in my code, sorry.