aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/api/util/GT_OverclockCalculator.java
blob: 6636b27bc7cfaa34c35357fda06f3e7867831803 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
package gregtech.api.util;

import javax.annotation.Nonnull;

public class GT_OverclockCalculator {

    /**
     * mAmps - Amperage of the multiblock
     * mEUt - Voltage of the multiblock
     * mRecipeEUt - Voltage the recipe will run at
     * mRecipeAmps - The amount of amps the recipe needs
     */
    private long mAmps = 1, mEUt = 0, mRecipeEUt = 0, mRecipeAmps = 1;
    /**
     * mEUtDiscount - Discount for EUt at the beginning of calculating overclocks, like GT++ machines
     * mSpeedBoost - Speeding/Slowing up/down the duration of a recipe at the beginning of calculating overclocks, like
     * GT++ machines
     * mHeatDiscountAmount - The value used for discount final eut per 900 heat
     */
    private double mEUtDiscount = 1, mSpeedBoost = 1, mHeatDiscountAmount = 0.95f;
    /**
     * mEUtIncreasePerOC - How much the bits should be moved to the left when it is overclocking (Going up, 2 meaning
     * it is multiplied with 4x)
     * mDurationDecreasePerOC - How much the bits should be moved to the right when its overclocking (Going down, 1
     * meaning it is halved)
     * mDuration - Duration of the recipe
     * mParallel - The parallel the multi has when trying to overclock
     * mRecipeHeat - The min heat required for the recipe
     * mMultiHeat - The heat the multi has when starting the recipe
     * mHeatPerfectOC - How much the bits should be moved to the right for each 1800 above recipe heat (Used for
     * duration)
     */
    private int mEUtIncreasePerOC = 2, mDurationDecreasePerOC = 1, mDuration = 0, mParallel = 1, mRecipeHeat = 0,
        mMultiHeat = 0, mHeatPerfectOC = 2;
    /**
     * mHeatOC - Whether to enable overclocking with heat like the EBF every 1800 heat difference
     * mOneTickDiscount - Whether to give EUt Discount when the duration goes below one tick
     * calculates - variable to check whether the overclocks have been calculated
     * mHeatDiscount - Whether to enable heat discounts every 900 heat difference
     */
    private boolean mHeatOC, mOneTickDiscount, calculated, mHeatDiscount;

    private static final int HEAT_DISCOUNT_THRESHOLD = 900;
    private static final int HEAT_PERFECT_OVERCLOCK_THRESHOLD = 1800;

    /**
     * Creates calculator that doesn't do OC at all.
     */
    public static GT_OverclockCalculator ofNoOverclock(@Nonnull GT_Recipe recipe) {
        return new GT_OverclockCalculator().setRecipeEUt(recipe.mEUt)
            .setDuration(recipe.mDuration)
            .setEUt(recipe.mEUt);
    }

    /**
     * An Overclock helper for calculating overclocks in many different situations
     */
    public GT_OverclockCalculator() {}

    /**
     * @param aRecipeEUt Sets the Recipe's starting voltage
     */
    public GT_OverclockCalculator setRecipeEUt(long aRecipeEUt) {
        mRecipeEUt = aRecipeEUt;
        return this;
    }

    /**
     * @param aEUt Sets the EUt that the multiblock can use. This is the voltage of the multi
     */
    public GT_OverclockCalculator setEUt(long aEUt) {
        mEUt = aEUt;
        return this;
    }

    /**
     * @param aDuration Sets the duration of the recipe
     */
    public GT_OverclockCalculator setDuration(int aDuration) {
        mDuration = aDuration;
        return this;
    }

    /**
     * @param aAmps Sets the Amperage that the multi can support
     */
    public GT_OverclockCalculator setAmperage(long aAmps) {
        mAmps = aAmps;
        return this;
    }

    /**
     * @param aRecipeAmps Sets the Amperage of the recipe
     */
    public GT_OverclockCalculator setRecipeAmperage(long aRecipeAmps) {
        mRecipeAmps = aRecipeAmps;
        return this;
    }

    /**
     * Enables Perfect OC in calculation
     */
    public GT_OverclockCalculator enablePerfectOC() {
        mDurationDecreasePerOC = 2;
        return this;
    }

    /**
     * Enables calculating overclocking using EBF's perfectOC
     */
    public GT_OverclockCalculator enableHeatOC() {
        mHeatOC = true;
        return this;
    }

    /**
     * Enables adding a heat discount at the end of calculating an overclock, just like the EBF
     */
    public GT_OverclockCalculator enableHeatDiscount() {
        mHeatDiscount = true;
        return this;
    }

    /**
     * Sets the starting heat of the recipe
     */
    public GT_OverclockCalculator setRecipeHeat(int aRecipeHeat) {
        mRecipeHeat = aRecipeHeat;
        return this;
    }

    /**
     * Sets the heat of the coils on the multi
     */
    public GT_OverclockCalculator setMultiHeat(int aMultiHeat) {
        mMultiHeat = aMultiHeat;
        return this;
    }

    /**
     * Sets an EUtDiscount. 0.9 is 10% less energy. 1.1 is 10% more energy
     */
    public GT_OverclockCalculator setEUtDiscount(float aEUtDiscount) {
        mEUtDiscount = aEUtDiscount;
        return this;
    }

    /**
     * Sets a Speed Boost for the multiblock. 0.9 is 10% faster. 1.1 is 10% slower
     */
    public GT_OverclockCalculator setSpeedBoost(float aSpeedBoost) {
        mSpeedBoost = aSpeedBoost;
        return this;
    }

    /**
     * Sets the parallel that the multiblock uses
     */
    public GT_OverclockCalculator setParallel(int aParallel) {
        mParallel = aParallel;
        return this;
    }

    /**
     * Sets the heat discount during OC calculation if HeatOC is used. Default: 0.95 = 5% discount Used like a EU/t
     * Discount
     */
    public GT_OverclockCalculator setHeatDiscount(float aHeatDiscount) {
        mHeatDiscountAmount = aHeatDiscount;
        return this;
    }

    /**
     * Sets the Overclock that should be calculated when one. This uses BitShifting! Default is 2, which is a 4x
     * decrease
     */
    public GT_OverclockCalculator setHeatPerfectOC(int aHeatPerfectOC) {
        mHeatPerfectOC = aHeatPerfectOC;
        return this;
    }

    /**
     * Sets the amount that the EUt increases per overclock. This uses BitShifting! Default is 2, which is a 4x increase
     */
    public GT_OverclockCalculator setEUtIncreasePerOC(int aEUtIncreasePerOC) {
        mEUtIncreasePerOC = aEUtIncreasePerOC;
        return this;
    }

    /**
     * Sets the amount that the duration decreases per overclock. This uses BitShifting! Default is 1, which halves the
     * duration
     */
    public GT_OverclockCalculator setDurationDecreasePerOC(int aDurationDecreasePerOC) {
        mDurationDecreasePerOC = aDurationDecreasePerOC;
        return this;
    }

    /**
     * Enables One Tick Discount on EUt based on Duration Decrease Per Overclock. This functions the same as single
     * blocks.
     */
    public GT_OverclockCalculator enableOneTickDiscount() {
        mOneTickDiscount = true;
        return this;
    }

    /**
     * Call this when all values have been put it.
     */
    public GT_OverclockCalculator calculate() {
        calculateOverclock();
        calculated = true;
        return this;
    }

    private void calculateOverclock() {
        if (mRecipeEUt > mEUt || mRecipeHeat > mMultiHeat) {
            mRecipeEUt = Long.MAX_VALUE;
            mDuration = Integer.MAX_VALUE;
            return;
        }
        int heatDiscounts = mHeatDiscount ? (mMultiHeat - mRecipeHeat) / HEAT_DISCOUNT_THRESHOLD : 0;
        double heatDiscountMultiplier = Math.pow(mHeatDiscountAmount, heatDiscounts);
        mDuration = (int) Math.ceil(mDuration * mSpeedBoost);
        if (mHeatOC) {
            while (mRecipeHeat + HEAT_PERFECT_OVERCLOCK_THRESHOLD <= mMultiHeat
                && (long) Math.ceil(mRecipeEUt * mParallel * mRecipeAmps * mEUtDiscount * heatDiscountMultiplier) << 2
                    < mEUt * mAmps) {
                if (mDuration < 1) {
                    break;
                }
                mRecipeEUt <<= mEUtIncreasePerOC;
                mDuration >>= mHeatPerfectOC;
                mRecipeHeat += HEAT_PERFECT_OVERCLOCK_THRESHOLD;
            }
        }

        int tRecipeTier = GT_Utility.getTier(mRecipeEUt);
        if (tRecipeTier == 0) {
            int tTier = GT_Utility.getTier(mEUt);
            int tTierDifference = tTier - 1;
            long tNextConsumption = ((long) Math
                .ceil(mRecipeEUt * mParallel * mRecipeAmps * mEUtDiscount * heatDiscountMultiplier))
                << mEUtIncreasePerOC;
            while (tTierDifference > 0 && tNextConsumption < mEUt * mAmps) {
                if (mDuration <= 1) {
                    break;
                }
                mRecipeEUt <<= mEUtIncreasePerOC;
                mDuration >>= mDurationDecreasePerOC;
                tNextConsumption <<= mEUtIncreasePerOC;
                tTierDifference--;
            }
        } else {
            long tNextConsumption = ((long) Math
                .ceil(mRecipeEUt * mParallel * mRecipeAmps * mEUtDiscount * heatDiscountMultiplier))
                << mEUtIncreasePerOC;
            while (tNextConsumption < mEUt * mAmps) {
                if (mDuration <= 1) {
                    break;
                }
                mRecipeEUt <<= mEUtIncreasePerOC;
                mDuration >>= mDurationDecreasePerOC;
                tNextConsumption <<= mEUtIncreasePerOC;
            }
        }

        if (mDuration < 1) {
            mDuration = 1;
        }

        if (mOneTickDiscount) {
            int voltageDifference = GT_Utility.getTier(mEUt) - GT_Utility.getTier(mRecipeEUt);
            mRecipeEUt >>= (long) voltageDifference * mDurationDecreasePerOC;
            if (mRecipeEUt < 1) {
                mRecipeEUt = 1;
            }
        }

        mRecipeEUt = (long) Math.ceil(mRecipeEUt * mParallel * mRecipeAmps * mEUtDiscount * heatDiscountMultiplier);
    }

    /**
     * @return The consumption after overclock has been calculated
     */
    public long getConsumption() {
        if (!calculated) {
            calculate();
        }
        return mRecipeEUt;
    }

    /**
     * @return The duration of the recipe after overclock has been calculated
     */
    public int getDuration() {
        if (!calculated) {
            calculate();
        }
        return mDuration;
    }
}